diff --git a/README.md b/README.md index f4e40653..954a29f5 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ All supported tools are presented in this file[BBFDM Tools](./docs/guide/tools.m * [Explain the different Network Deployment Scenarios](./docs/guide/network_depoyment_scenarios.md) * [How to Configure MACVLAN](./docs/guide/macvlan_interface.md) * [Explain Policy Based Routing Management](./docs/guide/policy_based_routing.md) +* [TR181 DNS datamodel](./docs/guide/device_dns.md) ## External dependencies for datamodel objects diff --git a/docs/guide/device_dns.md b/docs/guide/device_dns.md new file mode 100644 index 00000000..e77c4fe8 --- /dev/null +++ b/docs/guide/device_dns.md @@ -0,0 +1,75 @@ +# TR181 DNS datamodel + +Aim of this document is to explain how the DNS Client and Relay datamodel objects are mapped in dnsmasq uci. + +As per the definition in TR-181, Device.DNS.Client resolves FQDN on behalf of device internal application and Device.DNS.Relay allows the forwarding of local network DNS queries to local or external DNS servers. + +For DNS resolution `dnsmasq` package has been used and as per the default configuration of `dnsmasq` it listens on all interfaces and performs the role of both the DNS client and DNS relay by default. + +## Default config +```bash +config dnsmasq + option domainneeded '1' + option boguspriv '1' + option filterwin2k '0' + option localise_queries '1' + option rebind_protection '0' + option rebind_localhost '1' + option local '/lan/' + option domain 'lan' + option expandhosts '1' + option nonegcache '0' + option authoritative '1' + option readethers '1' + option leasefile '/tmp/dhcp.leases' + option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto' + option nonwildcard '1' + option localservice '1' + option dhcpscript '/usr/lib/dnsmasq/user-dhcp-script.sh' + option ednspacket_max '1232' +``` + +Now datamodel gives the provision to enable/disable DNS relay/client. So if any user disables the DNS relay that means resolution of the DNS queries from LAN network will stop but internal DNS queries from the device itself will be resolved and if the DNS client has been disabled then internal DNS queries will not resolve but DNS queries from LAN network should be resolved. + +To achieve this requirement whenever DNS client or relay object gets disabled we add a new section of dnsmasq in the UCI. This new section is then dedicated to DNS client and the section is named as `dns_client`, where as the existing dnsmasq section is then used for DNS relay only. We introduce two separate `dnsmasq` sections one for client and one for relay so that, at any point of time we can enable/disable the client and/or the relay without any effect to the other's work. + +## UCI with added new section for DNS client +```bash +config dnsmasq + option domainneeded '1' + option boguspriv '1' + option filterwin2k '0' + option localise_queries '1' + option rebind_protection '0' + option rebind_localhost '1' + option local '/lan/' + option domain 'lan' + option expandhosts '1' + option nonegcache '0' + option authoritative '1' + option readethers '1' + option leasefile '/tmp/dhcp.leases' + option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto' + option nonwildcard '1' + option localservice '1' + option dhcpscript '/usr/lib/dnsmasq/user-dhcp-script.sh' + option ednspacket_max '1232' + list notinterface 'loopback' + +config dnsmasq 'dns_client' + option domainneeded '1' + option boguspriv '1' + option filterwin2k '0' + option localise_queries '1' + option localservice '0' + option rebind_protection '0' + option rebind_localhost '1' + option expandhosts '1' + option nonegcache '0' + option authoritative '1' + option readethers '1' + option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto' + option nonwildcard '1' + option ednspacket_max '1232' + list interface 'loopback' +``` diff --git a/libbbfdm/dmtree/tr181/dhcpv4.c b/libbbfdm/dmtree/tr181/dhcpv4.c index e608cf70..fa33cbd4 100644 --- a/libbbfdm/dmtree/tr181/dhcpv4.c +++ b/libbbfdm/dmtree/tr181/dhcpv4.c @@ -12,6 +12,7 @@ */ #include "dhcpv4.h" +#include "dns.h" #define DHCP_OPTION_VENDORID 60 #define DHCP_OPTION_CLIENTID 61 @@ -570,12 +571,14 @@ static char *get_dhcp_option_name(int tag) /*#Device.DHCPv4.Server.Pool.{i}.!UCI:dhcp/dhcp/dmmap_dhcp*/ static int browseDHCPv4ServerPoolInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - char *ignore = NULL, *interface, *inst = NULL, *v; + char *ignore = NULL, *interface, *inst = NULL, *v, *instance; struct dhcp_args curr_dhcp_args = {0}; struct dmmap_dup *p = NULL; LIST_HEAD(leases); LIST_HEAD(dup_list); + char *relay_sec = get_dnsmasq_section_name(); + synchronize_specific_config_sections_with_dmmap("dhcp", "dhcp", "dmmap_dhcp", &dup_list); if (!list_empty(&dup_list)) @@ -588,6 +591,11 @@ static int browseDHCPv4ServerPoolInst(struct dmctx *dmctx, DMNODE *parent_node, if (ignore && DM_LSTRCMP(ignore, "1") == 0) continue; + // if dns_relay instance not present, add in the section + dmuci_get_value_by_section_string(p->config_section, "instance", &instance); + if (DM_STRLEN(instance) == 0) + dmuci_set_value_by_section(p->config_section, "instance", relay_sec); + dmuci_get_value_by_section_string(p->config_section, "interface", &interface); init_dhcp_args(&curr_dhcp_args, p, interface); @@ -995,6 +1003,7 @@ static int addObjDHCPv4ServerPool(char *refparam, struct dmctx *ctx, void *data, dmuci_rename_section_by_section(s, dhcp_sname); dmuci_set_value_by_section(s, "ignore", "0"); dmuci_set_value_by_section(s, "dhcpv4", "disabled"); + dmuci_set_value_by_section(s, "instance", get_dnsmasq_section_name()); // Defaults to uci defaults value dmuci_set_value_by_section(s, "start", "100"); dmuci_set_value_by_section(s, "limit", "150"); @@ -2776,13 +2785,19 @@ static int set_DHCPv4ClientReqOption_Tag(char *refparam, struct dmctx *ctx, void /*#Device.DHCPv4.Server.Enable!UCI:dhcp/dnsmasq,@dnsmasq[0]/dhcpv4server*/ static int get_DHCPv4Server_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmuci_get_option_value_fallback_def("dhcp", "@dnsmasq[0]", "dhcpv4server", "1"); + char *sec = get_dnsmasq_section_name(); + + if (DM_STRLEN(sec) == 0) + return 0; + + *value = dmuci_get_option_value_fallback_def("dhcp", sec, "dhcpv4server", "1"); return 0; } static int set_DHCPv4Server_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { bool b; + char *sec; switch (action) { case VALUECHECK: @@ -2790,8 +2805,12 @@ static int set_DHCPv4Server_Enable(char *refparam, struct dmctx *ctx, void *data return FAULT_9007; return 0; case VALUESET: + sec = get_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + string_to_bool(value, &b); - dmuci_set_value("dhcp", "@dnsmasq[0]", "dhcpv4server", b ? "1" : "0"); + dmuci_set_value("dhcp", sec, "dhcpv4server", b ? "1" : "0"); return 0; } return 0; diff --git a/libbbfdm/dmtree/tr181/dns.c b/libbbfdm/dmtree/tr181/dns.c index 1c2c6fe5..2f4fc811 100644 --- a/libbbfdm/dmtree/tr181/dns.c +++ b/libbbfdm/dmtree/tr181/dns.c @@ -11,6 +11,20 @@ #include "dmdiagnostics.h" #include "dns.h" +/* Returns dnsmasq section name belongs to LAN network */ +char *get_dnsmasq_section_name(void) +{ + struct uci_section *s = NULL; + + uci_foreach_sections("dhcp", "dnsmasq", s) { + char *sec = section_name(s); + if (DM_STRCMP(sec, "dns_client") != 0) + return sec; + } + + return ""; +} + /************************************************************* * COMMON FUNCTIONS **************************************************************/ @@ -125,6 +139,57 @@ static int dmmap_synchronizeDNSClientRelayServer(struct dmctx *dmctx, DMNODE *pa return 0; } +static void sync_dns_client_relay_section(void) +{ + struct uci_section *s = NULL; + struct uci_section *relay_sec = NULL; + struct uci_section *client_sec = NULL; + + uci_foreach_sections("dhcp", "dnsmasq", s) { + char *name = section_name(s); + if (DM_STRCMP(name, "dns_client") == 0) + client_sec = s; + else + relay_sec = s; + } + + if (client_sec) // already synced + return; + + if (relay_sec) { + s = NULL; + uci_foreach_sections("dhcp", "dhcp", s) { + char *str; + dmuci_get_value_by_section_string(s, "ignore", &str); + if (str[0] == '1') + continue; + + dmuci_set_value_by_section(s, "instance", section_name(relay_sec)); + } + + dmuci_add_list_value_by_section(relay_sec, "notinterface", "loopback"); + } + + dmuci_add_section("dhcp", "dnsmasq", &client_sec); + dmuci_rename_section_by_section(client_sec, "dns_client"); + dmuci_set_value_by_section(client_sec, "domainneeded", "1"); + dmuci_set_value_by_section(client_sec, "boguspriv", "1"); + dmuci_set_value_by_section(client_sec, "filterwin2k", "0"); + dmuci_set_value_by_section(client_sec, "localise_queries", "1"); + dmuci_set_value_by_section(client_sec, "localservice", "0"); + dmuci_set_value_by_section(client_sec, "rebind_protection", "0"); + dmuci_set_value_by_section(client_sec, "rebind_localhost", "1"); + dmuci_set_value_by_section(client_sec, "expandhosts", "1"); + dmuci_set_value_by_section(client_sec, "nonegcache", "0"); + dmuci_set_value_by_section(client_sec, "authoritative", "1"); + dmuci_set_value_by_section(client_sec, "readethers", "1"); + dmuci_set_value_by_section(client_sec, "resolvfile", + dmuci_get_value_by_section_fallback_def(relay_sec, "resolvfile", "/tmp/resolv.conf.d/resolv.conf.auto")); + dmuci_set_value_by_section(client_sec, "nonwildcard", "1"); + dmuci_set_value_by_section(client_sec, "ednspacket_max", "1232"); + dmuci_add_list_value_by_section(client_sec, "interface", "loopback"); +} + /************************************************************* * ENTRY METHOD **************************************************************/ @@ -222,13 +287,19 @@ static int get_dns_supported_record_types(char *refparam, struct dmctx *ctx, voi static int get_client_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = "1"; + char *v; + + dmuci_get_option_value_string("dhcp", "dns_client", "port", &v); + *value = (*v == '0') ? "0" : "1"; return 0; } static int get_client_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = "Enabled"; + char *v; + + dmuci_get_option_value_string("dhcp", "dns_client", "port", &v); + *value = (*v == '0') ? "Disabled" : "Enabled"; return 0; } @@ -291,17 +362,27 @@ static int get_dns_type(char *refparam, struct dmctx *ctx, void *data, char *ins static int get_relay_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - char *path = "/etc/rc.d/*dnsmasq"; - if (check_file(path)) - *value = "1"; - else - *value = "0"; + char *v, *sec; + + sec = get_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + + dmuci_get_option_value_string("dhcp", sec, "port", &v); + *value = (*v == '0') ? "0" : "1"; return 0; } static int get_relay_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = (check_file("/etc/rc.d/*dnsmasq")) ? "Enabled" : "Disabled"; + char *v, *sec; + + sec = get_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + + dmuci_get_option_value_string("dhcp", sec, "port", &v); + *value = (*v == '0') ? "Disabled" : "Enabled"; return 0; } @@ -426,12 +507,19 @@ static int get_result_response_time(char *refparam, struct dmctx *ctx, void *dat static int set_client_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { + bool b; + + sync_dns_client_relay_section(); + switch (action) { case VALUECHECK: if (bbfdm_validate_boolean(ctx, value)) return FAULT_9007; break; case VALUESET: + string_to_bool(value, &b); + char *port = b ? "" : "0"; + dmuci_set_value("dhcp", "dns_client", "port", port); break; } return 0; @@ -570,6 +658,9 @@ static int set_dns_interface(char *refparam, struct dmctx *ctx, void *data, char static int set_relay_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { bool b; + char *port, *sec; + + sync_dns_client_relay_section(); switch (action) { case VALUECHECK: @@ -577,8 +668,13 @@ static int set_relay_enable(char *refparam, struct dmctx *ctx, void *data, char return FAULT_9007; break; case VALUESET: + sec = get_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + string_to_bool(value, &b); - dmcmd("/etc/init.d/dnsmasq", 1, b ? "enable" : "disable"); + port = b ? "" : "0"; + dmuci_set_value("dhcp", sec, "port", port); break; } return 0; diff --git a/libbbfdm/dmtree/tr181/dns.h b/libbbfdm/dmtree/tr181/dns.h index 14c2ceff..d3042e61 100644 --- a/libbbfdm/dmtree/tr181/dns.h +++ b/libbbfdm/dmtree/tr181/dns.h @@ -27,4 +27,5 @@ extern DMLEAF tDNSDiagnosticsNSLookupDiagnosticsParams[]; extern DMOBJ tDNSDiagnosticsNSLookupDiagnosticsObj[]; extern DMLEAF tDNSDiagnosticsNSLookupDiagnosticsResultParams[]; +char *get_dnsmasq_section_name(void); #endif diff --git a/libbbfdm/dmtree/tr181/routeradvertisement.c b/libbbfdm/dmtree/tr181/routeradvertisement.c index b91cf432..65fa3d9a 100644 --- a/libbbfdm/dmtree/tr181/routeradvertisement.c +++ b/libbbfdm/dmtree/tr181/routeradvertisement.c @@ -9,6 +9,7 @@ */ #include "dhcpv4.h" +#include "dns.h" #include "routeradvertisement.h" struct radv_option_args { @@ -193,13 +194,19 @@ static int delObjRouterAdvertisementInterfaceSettingOption(char *refparam, struc /*#Device.RouterAdvertisement.Enable!UCI:dhcp/dnsmasq,@dnsmasq[0]/raserver*/ static int get_RouterAdvertisement_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmuci_get_option_value_fallback_def("dhcp", "@dnsmasq[0]", "raserver", "1"); + char *sec = get_dnsmasq_section_name(); + + if (DM_STRLEN(sec) == 0) + return 0; + + *value = dmuci_get_option_value_fallback_def("dhcp", sec, "raserver", "1"); return 0; } static int set_RouterAdvertisement_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { bool b; + char *sec; switch (action) { case VALUECHECK: @@ -207,8 +214,12 @@ static int set_RouterAdvertisement_Enable(char *refparam, struct dmctx *ctx, voi return FAULT_9007; break; case VALUESET: + sec = get_dnsmasq_section_name(); + if (DM_STRLEN(sec) == 0) + return 0; + string_to_bool(value, &b); - dmuci_set_value("dhcp", "@dnsmasq[0]", "raserver", b ? "1" : "0"); + dmuci_set_value("dhcp", sec, "raserver", b ? "1" : "0"); break; } return 0;