All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 02/11] netconfig: Add DHCP override and static IP API
@ 2022-04-18 19:15 Denis Kenzior
  0 siblings, 0 replies; 3+ messages in thread
From: Denis Kenzior @ 2022-04-18 19:15 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7738 bytes --]

Hi Andrew,

On 4/11/22 09:20, Andrew Zaborowski wrote:
> Add API to override things like DNS, gateway/router address, domain
> names, etc. received from DHCP or disable DHCP completely by setting
> a static address.
> ---
>   ell/ell.sym     |   8 +
>   ell/netconfig.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++-
>   ell/netconfig.h |  16 ++
>   3 files changed, 432 insertions(+), 5 deletions(-)
> 

<snip>

> +LIB_EXPORT bool l_netconfig_set_static_addr(struct l_netconfig *netconfig,
> +					uint8_t family,
> +					const struct l_rtnl_address *addr)
> +{
> +	if (unlikely(!netconfig || netconfig->started))
> +		return false;
> +
> +	if (addr && l_rtnl_address_get_family(addr) != family)
> +		return false;
> +
> +	switch (family) {
> +	case AF_INET:
> +		l_rtnl_address_free(l_steal_ptr(netconfig->v4_static_addr));
> +
> +		if (addr)
> +			break;

I take it this should be !addr?

> +
> +		netconfig->v4_static_addr = l_rtnl_address_clone(addr);
> +		l_rtnl_address_set_lifetimes(netconfig->v4_static_addr, 0, 0);
> +
> +		/*
> +		 * We could leave the decision about this flag up to the
> +		 * caller but for simplicity override to true.
> +		 */
> +		l_rtnl_address_set_noprefixroute(netconfig->v4_static_addr,
> +							true);
> +		return true;
> +	case AF_INET6:
> +		l_rtnl_address_free(l_steal_ptr(netconfig->v6_static_addr));
> +
> +		if (addr)
> +			break;
> +

And here as well?

> +		netconfig->v6_static_addr = l_rtnl_address_clone(addr);
> +		l_rtnl_address_set_lifetimes(netconfig->v6_static_addr, 0, 0);
> +		l_rtnl_address_set_noprefixroute(netconfig->v6_static_addr,
> +							true);
> +		return true;
> +	}
> +
> +	return false;
> +}
> +

<snip>

> +static bool netconfig_check_v4_config(struct l_netconfig *netconfig)
> +{
> +	struct in_addr local;
> +	struct in_addr gateway;
> +	uint8_t prefix_len = 0;
> +	unsigned int dns_num = 0;
> +	_auto_(l_free) struct in_addr *dns_list = NULL;
> +
> +	if (!netconfig->v4_enabled)
> +		return true;
> +
> +	if (netconfig->v4_static_addr) {
> +		char str[INET_ADDRSTRLEN];
> +
> +		prefix_len = l_rtnl_address_get_prefix_length(
> +						netconfig->v4_static_addr);
> +		if (prefix_len > 30)
> +			return false;
> +
> +		l_rtnl_address_get_address(netconfig->v4_static_addr, str);
> +		inet_pton(AF_INET, str, &local);
> +	}
> +
> +	if (netconfig->v4_gateway_override) {
> +		if (inet_pton(AF_INET, netconfig->v4_gateway_override,
> +				&gateway) != 1)
> +			return false;
> +	}
> +
> +	if (netconfig->v4_dns_override &&
> +			(dns_num = l_strv_length(netconfig->v4_dns_override))) {
> +		unsigned int i;
> +
> +		dns_list = l_new(struct in_addr, dns_num);
> +
> +		for (i = 0; i < dns_num; i++)
> +			if (inet_pton(AF_INET, netconfig->v4_dns_override[i],
> +					&dns_list[i]) != 1)
> +				return false;
> +	}
> +
> +	/*
> +	 * If using a static IP, we can validate right now that the gateway is
> +	 * in the local subnet.
> +	 */
> +	if (netconfig->v4_static_addr && netconfig->v4_gateway_override)
> +		if (!l_net_subnet_matches(&local, &gateway, prefix_len))
> +			return false;
> +
> +	/*
> +	 * If using a static IP and there's no gateway all the DNSes mut be on

typo: mut -> must

> +	 * the local subnet too.
> +	 */
> +	if (netconfig->v4_static_addr && !netconfig->v4_gateway_override &&
> +			netconfig->v4_dns_override) {
> +		unsigned int i;
> +
> +		for (i = 0; i < dns_num; i++)
> +			if (!l_net_subnet_matches(&local, &dns_list[i],
> +							prefix_len))
> +				return false;
> +	}
> +
> +	return true;
> +}
> +
> +static bool netconfig_check_v6_config(struct l_netconfig *netconfig)
> +{
> +	struct in_addr local;
> +	struct in_addr gateway;
> +	uint8_t prefix_len = 0;
> +	unsigned int dns_num = 0;
> +	_auto_(l_free) struct in6_addr *dns_list = NULL;
> +
> +	if (!netconfig->v6_enabled)
> +		return true;
> +
> +	if (netconfig->v6_static_addr) {
> +		char str[INET6_ADDRSTRLEN];
> +
> +		prefix_len = l_rtnl_address_get_prefix_length(
> +						netconfig->v6_static_addr);
> +		if (prefix_len > 126)
> +			return false;
> +
> +		l_rtnl_address_get_address(netconfig->v6_static_addr, str);
> +		inet_pton(AF_INET6, str, &local);
> +	}
> +
> +	if (netconfig->v6_gateway_override) {
> +		if (inet_pton(AF_INET6, netconfig->v6_gateway_override,
> +				&gateway) != 1)
> +			return false;
> +	}
> +
> +	if (netconfig->v6_dns_override &&
> +			(dns_num = l_strv_length(netconfig->v6_dns_override))) {
> +		unsigned int i;
> +
> +		dns_list = l_new(struct in6_addr, dns_num);
> +
> +		for (i = 0; i < dns_num; i++)
> +			if (inet_pton(AF_INET6, netconfig->v6_dns_override[i],
> +					&dns_list[i]) != 1)
> +				return false;
> +	}
> +
> +	/*
> +	 * If using a static IP, we can validate right now that the gateway is
> +	 * in the local subnet.
> +	 */
> +	if (netconfig->v6_static_addr && netconfig->v6_gateway_override)
> +		if (!l_net_subnet_matches(&local, &gateway, prefix_len))
> +			return false;

Not sure this is true?  AFAIK the default gateway could be a link local address...

> +
> +	/*
> +	 * If using a static IP and there's no gateway all the DNSes mut be on

Same typo as above.

> +	 * the local subnet too.
> +	 */
> +	if (netconfig->v6_static_addr && !netconfig->v6_gateway_override &&
> +			netconfig->v6_dns_override) {
> +		unsigned int i;
> +
> +		for (i = 0; i < dns_num; i++)
> +			if (!l_net_subnet_matches(&local, &dns_list[i],
> +							prefix_len))
> +				return false;

This whole block maybe should be a static convenience function?  In fact, much 
of these checks are the same as in v4 version of this function and could be 
combined?

> +	}
> +
> +	return true;
> +}
> +

<snip>

>   LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
>   {
>   	if (unlikely(!netconfig || netconfig->started))
>   		return false;
>   
> -	if (netconfig->v4_enabled &&
> -			!l_dhcp_client_start(netconfig->dhcp_client))
> +	if (!netconfig_check_config(netconfig))
>   		return false;
>  

Can we check that both v4_enabled and v6_enabled are false and return appropriately?

> -	netconfig->started = true;
> +	if (netconfig->v4_enabled) {

I'd prefer less nesting, so something like:

if (!netconfig->v4_enabled)
	goto configure_ipv6;

> +		if (netconfig->v4_static_addr) {
> +			/*
> +			 * We're basically ready to configure the interface
> +			 * but do this in an idle callback.
> +			 */
> +			netconfig->do_static_work = l_idle_create(
> +						netconfig_do_static_config,
> +						netconfig, NULL);

goto here..

> +		} else {
> +			if (!l_dhcp_client_start(netconfig->dhcp_client))
> +				return false;
> +		}
> +	}
>   
> +	netconfig->started = true;
>   	return true;
>   }
>   

<snip>

> diff --git a/ell/netconfig.h b/ell/netconfig.h
> index 682f4aa..aab9d3f 100644
> --- a/ell/netconfig.h
> +++ b/ell/netconfig.h
> @@ -53,6 +53,22 @@ typedef void (*l_netconfig_destroy_cb_t)(void *user_data);
>   
>   struct l_netconfig *l_netconfig_new(uint32_t ifindex);
>   void l_netconfig_destroy(struct l_netconfig *netconfig);
> +bool l_netconfig_set_af_enabled(struct l_netconfig *netconfig, uint8_t family,
> +				bool enabled);

Can we call it family_enabled?

> +bool l_netconfig_set_static_addr(struct l_netconfig *netconfig, uint8_t family,
> +					const struct l_rtnl_address *addr);
> +bool l_netconfig_set_gateway_override(struct l_netconfig *netconfig,
> +					uint8_t family,
> +					const char *gateway_str);

Wonder why you use l_rtnl_address for 'set_static_addr' and a string for the 
gateway?

Regards,
-Denis

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 02/11] netconfig: Add DHCP override and static IP API
@ 2022-04-19  7:59 Andrew Zaborowski
  0 siblings, 0 replies; 3+ messages in thread
From: Andrew Zaborowski @ 2022-04-19  7:59 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5525 bytes --]

On Mon, 18 Apr 2022 at 21:15, Denis Kenzior <denkenz(a)gmail.com> wrote:
> On 4/11/22 09:20, Andrew Zaborowski wrote:
> > +     switch (family) {
> > +     case AF_INET:
> > +             l_rtnl_address_free(l_steal_ptr(netconfig->v4_static_addr));
> > +
> > +             if (addr)
> > +                     break;
>
> I take it this should be !addr?

Yep.

>
> > +
> > +             netconfig->v4_static_addr = l_rtnl_address_clone(addr);
> > +             l_rtnl_address_set_lifetimes(netconfig->v4_static_addr, 0, 0);
> > +
> > +             /*
> > +              * We could leave the decision about this flag up to the
> > +              * caller but for simplicity override to true.
> > +              */
> > +             l_rtnl_address_set_noprefixroute(netconfig->v4_static_addr,
> > +                                                     true);
> > +             return true;
> > +     case AF_INET6:
> > +             l_rtnl_address_free(l_steal_ptr(netconfig->v6_static_addr));
> > +
> > +             if (addr)
> > +                     break;
> > +
>
> And here as well?

Yep.

> > +     /*
> > +      * If using a static IP and there's no gateway all the DNSes mut be on
>
> typo: mut -> must

Right.

>
> > +     /*
> > +      * If using a static IP, we can validate right now that the gateway is
> > +      * in the local subnet.
> > +      */
> > +     if (netconfig->v6_static_addr && netconfig->v6_gateway_override)
> > +             if (!l_net_subnet_matches(&local, &gateway, prefix_len))
> > +                     return false;
>
> Not sure this is true?  AFAIK the default gateway could be a link local address...

True, that's also a good catch.  I'll add a check for that (unless you
prefer we don't validate this address.)

>
> > +
> > +     /*
> > +      * If using a static IP and there's no gateway all the DNSes mut be on
>
> Same typo as above.
>
> > +      * the local subnet too.
> > +      */
> > +     if (netconfig->v6_static_addr && !netconfig->v6_gateway_override &&
> > +                     netconfig->v6_dns_override) {
> > +             unsigned int i;
> > +
> > +             for (i = 0; i < dns_num; i++)
> > +                     if (!l_net_subnet_matches(&local, &dns_list[i],
> > +                                                     prefix_len))
> > +                             return false;
>
> This whole block maybe should be a static convenience function?  In fact, much
> of these checks are the same as in v4 version of this function and could be
> combined?

Ok, let me try to combine them.

>
> > +     }
> > +
> > +     return true;
> > +}
> > +
>
> <snip>
>
> >   LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
> >   {
> >       if (unlikely(!netconfig || netconfig->started))
> >               return false;
> >
> > -     if (netconfig->v4_enabled &&
> > -                     !l_dhcp_client_start(netconfig->dhcp_client))
> > +     if (!netconfig_check_config(netconfig))
> >               return false;
> >
>
> Can we check that both v4_enabled and v6_enabled are false and return appropriately?

Ok.  We effectively do but let me add one at the beginning.

>
> > -     netconfig->started = true;
> > +     if (netconfig->v4_enabled) {
>
> I'd prefer less nesting, so something like:
>
> if (!netconfig->v4_enabled)
>         goto configure_ipv6;

Ok.

>
> > +             if (netconfig->v4_static_addr) {
> > +                     /*
> > +                      * We're basically ready to configure the interface
> > +                      * but do this in an idle callback.
> > +                      */
> > +                     netconfig->do_static_work = l_idle_create(
> > +                                             netconfig_do_static_config,
> > +                                             netconfig, NULL);
>
> goto here..
>
> > +             } else {
> > +                     if (!l_dhcp_client_start(netconfig->dhcp_client))
> > +                             return false;
> > +             }
> > +     }
> >
> > +     netconfig->started = true;
> >       return true;
> >   }
> >
>
> <snip>
>
> > diff --git a/ell/netconfig.h b/ell/netconfig.h
> > index 682f4aa..aab9d3f 100644
> > --- a/ell/netconfig.h
> > +++ b/ell/netconfig.h
> > @@ -53,6 +53,22 @@ typedef void (*l_netconfig_destroy_cb_t)(void *user_data);
> >
> >   struct l_netconfig *l_netconfig_new(uint32_t ifindex);
> >   void l_netconfig_destroy(struct l_netconfig *netconfig);
> > +bool l_netconfig_set_af_enabled(struct l_netconfig *netconfig, uint8_t family,
> > +                             bool enabled);
>
> Can we call it family_enabled?

Sure.

>
> > +bool l_netconfig_set_static_addr(struct l_netconfig *netconfig, uint8_t family,
> > +                                     const struct l_rtnl_address *addr);
> > +bool l_netconfig_set_gateway_override(struct l_netconfig *netconfig,
> > +                                     uint8_t family,
> > +                                     const char *gateway_str);
>
> Wonder why you use l_rtnl_address for 'set_static_addr' and a string for the
> gateway?

So l_rtnl_address includes the prefix length and such, so the struct
maps to our own addresses.  The gateway would map to the next-hop
address in the l_rtnl_route struct so it didn't seem fitting.  Note
that l_rtnl_route doesn't use l_rtnl_address for that in its API.

Best regards

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 02/11] netconfig: Add DHCP override and static IP API
@ 2022-04-11 14:20 Andrew Zaborowski
  0 siblings, 0 replies; 3+ messages in thread
From: Andrew Zaborowski @ 2022-04-11 14:20 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 15315 bytes --]

Add API to override things like DNS, gateway/router address, domain
names, etc. received from DHCP or disable DHCP completely by setting
a static address.
---
 ell/ell.sym     |   8 +
 ell/netconfig.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++-
 ell/netconfig.h |  16 ++
 3 files changed, 432 insertions(+), 5 deletions(-)

diff --git a/ell/ell.sym b/ell/ell.sym
index a03dc69..ec995fc 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -735,6 +735,14 @@ global:
 	/* netconfig */
 	l_netconfig_new;
 	l_netconfig_destroy;
+	l_netconfig_set_af_enabled;
+	l_netconfig_set_hostname;
+	l_netconfig_set_route_priority;
+	l_netconfig_set_static_addr;
+	l_netconfig_set_gateway_override;
+	l_netconfig_set_dns_override;
+	l_netconfig_set_domain_names_override;
+	l_netconfig_check_config;
 	l_netconfig_start;
 	l_netconfig_stop;
 	l_netconfig_get_dhcp_client;
diff --git a/ell/netconfig.c b/ell/netconfig.c
index 2808536..d0f87b3 100644
--- a/ell/netconfig.c
+++ b/ell/netconfig.c
@@ -37,16 +37,32 @@
 #include "rtnl.h"
 #include "queue.h"
 #include "time.h"
+#include "idle.h"
+#include "strv.h"
+#include "net.h"
 #include "netconfig.h"
 
 struct l_netconfig {
 	uint32_t ifindex;
-	bool v4_enabled;
-	bool started;
 	uint32_t route_priority;
 
+	bool v4_enabled;
+	struct l_rtnl_address *v4_static_addr;
+	char *v4_gateway_override;
+	char **v4_dns_override;
+	char **v4_domain_names_override;
+
+	bool v6_enabled;
+	struct l_rtnl_address *v6_static_addr;
+	char *v6_gateway_override;
+	char **v6_dns_override;
+	char **v6_domain_names_override;
+
+	bool started;
+	struct l_idle *do_static_work;
 	bool v4_configured;
 	struct l_dhcp_client *dhcp_client;
+
 	/* These objects, if not NULL, are owned by @addresses and @routes */
 	struct l_rtnl_address *v4_address;
 	struct l_rtnl_route *v4_subnet_route;
@@ -128,6 +144,11 @@ static void netconfig_add_v4_routes(struct l_netconfig *nc, const char *ip,
 
 	/* Gateway route */
 
+	if (nc->v4_gateway_override) {
+		gateway = nc->v4_gateway_override;
+		rtm_protocol = RTPROT_STATIC;
+	}
+
 	if (!gateway)
 		return;
 
@@ -310,6 +331,15 @@ LIB_EXPORT void l_netconfig_destroy(struct l_netconfig *netconfig)
 
 	l_netconfig_stop(netconfig);
 
+	l_netconfig_set_static_addr(netconfig, AF_INET, NULL);
+	l_netconfig_set_gateway_override(netconfig, AF_INET, NULL);
+	l_netconfig_set_dns_override(netconfig, AF_INET, NULL);
+	l_netconfig_set_domain_names_override(netconfig, AF_INET, NULL);
+	l_netconfig_set_static_addr(netconfig, AF_INET6, NULL);
+	l_netconfig_set_gateway_override(netconfig, AF_INET6, NULL);
+	l_netconfig_set_dns_override(netconfig, AF_INET6, NULL);
+	l_netconfig_set_domain_names_override(netconfig, AF_INET6, NULL);
+
 	l_dhcp_client_destroy(netconfig->dhcp_client);
 	l_netconfig_set_event_handler(netconfig, NULL, NULL, NULL);
 	l_queue_destroy(netconfig->addresses.current, NULL);
@@ -323,17 +353,387 @@ LIB_EXPORT void l_netconfig_destroy(struct l_netconfig *netconfig)
 	l_free(netconfig);
 }
 
+/*
+ * The following l_netconfig_set_* functions configure the l_netconfig's
+ * client settings.  The setters can be called independently, without
+ * following a specific order.  Most of the setters will not validate the
+ * values passed, l_netconfig_start() will fail if settings are incorrect
+ * or inconsistent between themselves, e.g. if the static local IP and
+ * gateway IP are not in the same subnet.  Alternatively
+ * l_netconfig_check_config() can be called at any point to validate the
+ * current configuration.  The configuration can only be changed while
+ * the l_netconfig state machine is stopped, i.e. before
+ * l_netconfig_start() and after l_netconfig_stop().
+ *
+ * l_netconfig_set_hostname, l_netconfig_set_static_addr,
+ * l_netconfig_set_gateway_override, l_netconfig_set_dns_override and
+ * l_netconfig_set_domain_names_override can be passed NULL to unset a
+ * value that had been set before (revert to auto).  This is why the
+ * family parameter is needed even when it could otherwise be derived
+ * from the new value that is passed.
+ */
+LIB_EXPORT bool l_netconfig_set_af_enabled(struct l_netconfig *netconfig,
+						uint8_t family, bool enabled)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	switch (family) {
+	case AF_INET:
+		netconfig->v4_enabled = enabled;
+		return true;
+	}
+
+	return false;
+}
+
+LIB_EXPORT bool l_netconfig_set_hostname(struct l_netconfig *netconfig,
+						const char *hostname)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	return l_dhcp_client_set_hostname(netconfig->dhcp_client, hostname);
+}
+
+LIB_EXPORT bool l_netconfig_set_route_priority(struct l_netconfig *netconfig,
+						uint32_t priority)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	netconfig->route_priority = priority;
+	return true;
+}
+
+LIB_EXPORT bool l_netconfig_set_static_addr(struct l_netconfig *netconfig,
+					uint8_t family,
+					const struct l_rtnl_address *addr)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	if (addr && l_rtnl_address_get_family(addr) != family)
+		return false;
+
+	switch (family) {
+	case AF_INET:
+		l_rtnl_address_free(l_steal_ptr(netconfig->v4_static_addr));
+
+		if (addr)
+			break;
+
+		netconfig->v4_static_addr = l_rtnl_address_clone(addr);
+		l_rtnl_address_set_lifetimes(netconfig->v4_static_addr, 0, 0);
+
+		/*
+		 * We could leave the decision about this flag up to the
+		 * caller but for simplicity override to true.
+		 */
+		l_rtnl_address_set_noprefixroute(netconfig->v4_static_addr,
+							true);
+		return true;
+	case AF_INET6:
+		l_rtnl_address_free(l_steal_ptr(netconfig->v6_static_addr));
+
+		if (addr)
+			break;
+
+		netconfig->v6_static_addr = l_rtnl_address_clone(addr);
+		l_rtnl_address_set_lifetimes(netconfig->v6_static_addr, 0, 0);
+		l_rtnl_address_set_noprefixroute(netconfig->v6_static_addr,
+							true);
+		return true;
+	}
+
+	return false;
+}
+
+LIB_EXPORT bool l_netconfig_set_gateway_override(struct l_netconfig *netconfig,
+							uint8_t family,
+							const char *gateway_str)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	switch (family) {
+	case AF_INET:
+		l_free(l_steal_ptr(netconfig->v4_gateway_override));
+
+		if (!gateway_str)
+			break;
+
+		netconfig->v4_gateway_override = l_strdup(gateway_str);
+		return true;
+	case AF_INET6:
+		l_free(l_steal_ptr(netconfig->v6_gateway_override));
+
+		if (!gateway_str)
+			break;
+
+		netconfig->v6_gateway_override = l_strdup(gateway_str);
+		return true;
+	}
+
+	return false;
+}
+
+LIB_EXPORT bool l_netconfig_set_dns_override(struct l_netconfig *netconfig,
+						uint8_t family, char **dns_list)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	switch (family) {
+	case AF_INET:
+		l_strv_free(l_steal_ptr(netconfig->v4_dns_override));
+
+		if (!dns_list)
+			break;
+
+		netconfig->v4_dns_override = l_strv_copy(dns_list);
+		return true;
+	case AF_INET6:
+		l_strv_free(l_steal_ptr(netconfig->v6_dns_override));
+
+		if (!dns_list)
+			break;
+
+		netconfig->v6_dns_override = l_strv_copy(dns_list);
+		return true;
+	}
+
+	return false;
+}
+
+LIB_EXPORT bool l_netconfig_set_domain_names_override(
+						struct l_netconfig *netconfig,
+						uint8_t family, char **names)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	switch (family) {
+	case AF_INET:
+		l_strv_free(l_steal_ptr(netconfig->v4_domain_names_override));
+
+		if (!names)
+			break;
+
+		netconfig->v4_domain_names_override = l_strv_copy(names);
+		return true;
+	case AF_INET6:
+		l_strv_free(l_steal_ptr(netconfig->v6_domain_names_override));
+
+		if (!names)
+			break;
+
+		netconfig->v6_domain_names_override = l_strv_copy(names);
+		return true;
+	}
+
+	return false;
+}
+
+static bool netconfig_check_v4_config(struct l_netconfig *netconfig)
+{
+	struct in_addr local;
+	struct in_addr gateway;
+	uint8_t prefix_len = 0;
+	unsigned int dns_num = 0;
+	_auto_(l_free) struct in_addr *dns_list = NULL;
+
+	if (!netconfig->v4_enabled)
+		return true;
+
+	if (netconfig->v4_static_addr) {
+		char str[INET_ADDRSTRLEN];
+
+		prefix_len = l_rtnl_address_get_prefix_length(
+						netconfig->v4_static_addr);
+		if (prefix_len > 30)
+			return false;
+
+		l_rtnl_address_get_address(netconfig->v4_static_addr, str);
+		inet_pton(AF_INET, str, &local);
+	}
+
+	if (netconfig->v4_gateway_override) {
+		if (inet_pton(AF_INET, netconfig->v4_gateway_override,
+				&gateway) != 1)
+			return false;
+	}
+
+	if (netconfig->v4_dns_override &&
+			(dns_num = l_strv_length(netconfig->v4_dns_override))) {
+		unsigned int i;
+
+		dns_list = l_new(struct in_addr, dns_num);
+
+		for (i = 0; i < dns_num; i++)
+			if (inet_pton(AF_INET, netconfig->v4_dns_override[i],
+					&dns_list[i]) != 1)
+				return false;
+	}
+
+	/*
+	 * If using a static IP, we can validate right now that the gateway is
+	 * in the local subnet.
+	 */
+	if (netconfig->v4_static_addr && netconfig->v4_gateway_override)
+		if (!l_net_subnet_matches(&local, &gateway, prefix_len))
+			return false;
+
+	/*
+	 * If using a static IP and there's no gateway all the DNSes mut be on
+	 * the local subnet too.
+	 */
+	if (netconfig->v4_static_addr && !netconfig->v4_gateway_override &&
+			netconfig->v4_dns_override) {
+		unsigned int i;
+
+		for (i = 0; i < dns_num; i++)
+			if (!l_net_subnet_matches(&local, &dns_list[i],
+							prefix_len))
+				return false;
+	}
+
+	return true;
+}
+
+static bool netconfig_check_v6_config(struct l_netconfig *netconfig)
+{
+	struct in_addr local;
+	struct in_addr gateway;
+	uint8_t prefix_len = 0;
+	unsigned int dns_num = 0;
+	_auto_(l_free) struct in6_addr *dns_list = NULL;
+
+	if (!netconfig->v6_enabled)
+		return true;
+
+	if (netconfig->v6_static_addr) {
+		char str[INET6_ADDRSTRLEN];
+
+		prefix_len = l_rtnl_address_get_prefix_length(
+						netconfig->v6_static_addr);
+		if (prefix_len > 126)
+			return false;
+
+		l_rtnl_address_get_address(netconfig->v6_static_addr, str);
+		inet_pton(AF_INET6, str, &local);
+	}
+
+	if (netconfig->v6_gateway_override) {
+		if (inet_pton(AF_INET6, netconfig->v6_gateway_override,
+				&gateway) != 1)
+			return false;
+	}
+
+	if (netconfig->v6_dns_override &&
+			(dns_num = l_strv_length(netconfig->v6_dns_override))) {
+		unsigned int i;
+
+		dns_list = l_new(struct in6_addr, dns_num);
+
+		for (i = 0; i < dns_num; i++)
+			if (inet_pton(AF_INET6, netconfig->v6_dns_override[i],
+					&dns_list[i]) != 1)
+				return false;
+	}
+
+	/*
+	 * If using a static IP, we can validate right now that the gateway is
+	 * in the local subnet.
+	 */
+	if (netconfig->v6_static_addr && netconfig->v6_gateway_override)
+		if (!l_net_subnet_matches(&local, &gateway, prefix_len))
+			return false;
+
+	/*
+	 * If using a static IP and there's no gateway all the DNSes mut be on
+	 * the local subnet too.
+	 */
+	if (netconfig->v6_static_addr && !netconfig->v6_gateway_override &&
+			netconfig->v6_dns_override) {
+		unsigned int i;
+
+		for (i = 0; i < dns_num; i++)
+			if (!l_net_subnet_matches(&local, &dns_list[i],
+							prefix_len))
+				return false;
+	}
+
+	return true;
+}
+
+static bool netconfig_check_config(struct l_netconfig *netconfig)
+{
+	/* TODO: error reporting through a debug log handler or otherwise */
+
+	return netconfig_check_v4_config(netconfig) &&
+		netconfig_check_v6_config(netconfig);
+}
+
+LIB_EXPORT bool l_netconfig_check_config(struct l_netconfig *netconfig)
+{
+	if (unlikely(!netconfig || netconfig->started))
+		return false;
+
+	return netconfig_check_config(netconfig);
+}
+
+static void netconfig_add_static_address_routes(struct l_netconfig *nc)
+{
+	char ip[INET_ADDRSTRLEN];
+	uint32_t prefix_len;
+
+	nc->v4_address = l_rtnl_address_clone(nc->v4_static_addr);
+	l_queue_push_tail(nc->addresses.current, nc->v4_address);
+	l_queue_push_tail(nc->addresses.added, nc->v4_address);
+
+	l_rtnl_address_get_address(nc->v4_static_addr, ip);
+	prefix_len = l_rtnl_address_get_prefix_length(nc->v4_static_addr);
+	netconfig_add_v4_routes(nc, ip, prefix_len, NULL, RTPROT_STATIC);
+}
+
+static void netconfig_do_static_config(struct l_idle *idle, void *user_data)
+{
+	struct l_netconfig *nc = user_data;
+
+	l_idle_remove(l_steal_ptr(nc->do_static_work));
+
+	if (nc->v4_static_addr && !nc->v4_configured) {
+		netconfig_add_static_address_routes(nc);
+		nc->v4_configured = true;
+		netconfig_emit_event(nc, AF_INET, L_NETCONFIG_EVENT_CONFIGURE);
+	}
+}
+
 LIB_EXPORT bool l_netconfig_start(struct l_netconfig *netconfig)
 {
 	if (unlikely(!netconfig || netconfig->started))
 		return false;
 
-	if (netconfig->v4_enabled &&
-			!l_dhcp_client_start(netconfig->dhcp_client))
+	if (!netconfig_check_config(netconfig))
 		return false;
 
-	netconfig->started = true;
+	if (netconfig->v4_enabled) {
+		if (netconfig->v4_static_addr) {
+			/*
+			 * We're basically ready to configure the interface
+			 * but do this in an idle callback.
+			 */
+			netconfig->do_static_work = l_idle_create(
+						netconfig_do_static_config,
+						netconfig, NULL);
+		} else {
+			if (!l_dhcp_client_start(netconfig->dhcp_client))
+				return false;
+		}
+	}
 
+	netconfig->started = true;
 	return true;
 }
 
@@ -344,6 +744,9 @@ LIB_EXPORT void l_netconfig_stop(struct l_netconfig *netconfig)
 
 	netconfig->started = false;
 
+	if (netconfig->do_static_work)
+		l_idle_remove(l_steal_ptr(netconfig->do_static_work));
+
 	netconfig_update_cleanup(netconfig);
 	l_queue_clear(netconfig->routes.current,
 			(l_queue_destroy_func_t) l_rtnl_route_free);
diff --git a/ell/netconfig.h b/ell/netconfig.h
index 682f4aa..aab9d3f 100644
--- a/ell/netconfig.h
+++ b/ell/netconfig.h
@@ -53,6 +53,22 @@ typedef void (*l_netconfig_destroy_cb_t)(void *user_data);
 
 struct l_netconfig *l_netconfig_new(uint32_t ifindex);
 void l_netconfig_destroy(struct l_netconfig *netconfig);
+bool l_netconfig_set_af_enabled(struct l_netconfig *netconfig, uint8_t family,
+				bool enabled);
+bool l_netconfig_set_hostname(struct l_netconfig *netconfig,
+				const char *hostname);
+bool l_netconfig_set_route_priority(struct l_netconfig *netconfig,
+					uint32_t priority);
+bool l_netconfig_set_static_addr(struct l_netconfig *netconfig, uint8_t family,
+					const struct l_rtnl_address *addr);
+bool l_netconfig_set_gateway_override(struct l_netconfig *netconfig,
+					uint8_t family,
+					const char *gateway_str);
+bool l_netconfig_set_dns_override(struct l_netconfig *netconfig, uint8_t family,
+					char **dns_list);
+bool l_netconfig_set_domain_names_override(struct l_netconfig *netconfig,
+						uint8_t family, char **names);
+bool l_netconfig_check_config(struct l_netconfig *netconfig);
 
 bool l_netconfig_start(struct l_netconfig *netconfig);
 void l_netconfig_stop(struct l_netconfig *netconfig);
-- 
2.32.0

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-04-19  7:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-18 19:15 [PATCH 02/11] netconfig: Add DHCP override and static IP API Denis Kenzior
  -- strict thread matches above, loose matches on Subject: below --
2022-04-19  7:59 Andrew Zaborowski
2022-04-11 14:20 Andrew Zaborowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.