1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "alloc-util.h"
4 #include "dns-domain.h"
5 #include "resolved-dns-search-domain.h"
6 #include "resolved-link.h"
7 #include "resolved-manager.h"
8 
dns_search_domain_new(Manager * m,DnsSearchDomain ** ret,DnsSearchDomainType type,Link * l,const char * name)9 int dns_search_domain_new(
10                 Manager *m,
11                 DnsSearchDomain **ret,
12                 DnsSearchDomainType type,
13                 Link *l,
14                 const char *name) {
15 
16         _cleanup_free_ char *normalized = NULL;
17         DnsSearchDomain *d;
18         int r;
19 
20         assert(m);
21         assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
22         assert(name);
23 
24         r = dns_name_normalize(name, 0, &normalized);
25         if (r < 0)
26                 return r;
27 
28         if (l) {
29                 if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
30                         return -E2BIG;
31         } else {
32                 if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX)
33                         return -E2BIG;
34         }
35 
36         d = new(DnsSearchDomain, 1);
37         if (!d)
38                 return -ENOMEM;
39 
40         *d = (DnsSearchDomain) {
41                 .n_ref = 1,
42                 .manager = m,
43                 .type = type,
44                 .name = TAKE_PTR(normalized),
45         };
46 
47         switch (type) {
48 
49         case DNS_SEARCH_DOMAIN_LINK:
50                 d->link = l;
51                 LIST_APPEND(domains, l->search_domains, d);
52                 l->n_search_domains++;
53                 break;
54 
55         case DNS_SERVER_SYSTEM:
56                 LIST_APPEND(domains, m->search_domains, d);
57                 m->n_search_domains++;
58                 break;
59 
60         default:
61                 assert_not_reached();
62         }
63 
64         d->linked = true;
65 
66         if (ret)
67                 *ret = d;
68 
69         return 0;
70 }
71 
dns_search_domain_free(DnsSearchDomain * d)72 static DnsSearchDomain* dns_search_domain_free(DnsSearchDomain *d) {
73         assert(d);
74 
75         free(d->name);
76         return mfree(d);
77 }
78 
79 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsSearchDomain, dns_search_domain, dns_search_domain_free);
80 
dns_search_domain_unlink(DnsSearchDomain * d)81 void dns_search_domain_unlink(DnsSearchDomain *d) {
82         assert(d);
83         assert(d->manager);
84 
85         if (!d->linked)
86                 return;
87 
88         switch (d->type) {
89 
90         case DNS_SEARCH_DOMAIN_LINK:
91                 assert(d->link);
92                 assert(d->link->n_search_domains > 0);
93                 LIST_REMOVE(domains, d->link->search_domains, d);
94                 d->link->n_search_domains--;
95                 break;
96 
97         case DNS_SEARCH_DOMAIN_SYSTEM:
98                 assert(d->manager->n_search_domains > 0);
99                 LIST_REMOVE(domains, d->manager->search_domains, d);
100                 d->manager->n_search_domains--;
101                 break;
102         }
103 
104         d->linked = false;
105 
106         dns_search_domain_unref(d);
107 }
108 
dns_search_domain_move_back_and_unmark(DnsSearchDomain * d)109 void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) {
110         DnsSearchDomain *tail;
111 
112         assert(d);
113 
114         if (!d->marked)
115                 return;
116 
117         d->marked = false;
118 
119         if (!d->linked || !d->domains_next)
120                 return;
121 
122         switch (d->type) {
123 
124         case DNS_SEARCH_DOMAIN_LINK:
125                 assert(d->link);
126                 LIST_FIND_TAIL(domains, d, tail);
127                 LIST_REMOVE(domains, d->link->search_domains, d);
128                 LIST_INSERT_AFTER(domains, d->link->search_domains, tail, d);
129                 break;
130 
131         case DNS_SEARCH_DOMAIN_SYSTEM:
132                 LIST_FIND_TAIL(domains, d, tail);
133                 LIST_REMOVE(domains, d->manager->search_domains, d);
134                 LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d);
135                 break;
136 
137         default:
138                 assert_not_reached();
139         }
140 }
141 
dns_search_domain_unlink_all(DnsSearchDomain * first)142 void dns_search_domain_unlink_all(DnsSearchDomain *first) {
143         DnsSearchDomain *next;
144 
145         if (!first)
146                 return;
147 
148         next = first->domains_next;
149         dns_search_domain_unlink(first);
150 
151         dns_search_domain_unlink_all(next);
152 }
153 
dns_search_domain_unlink_marked(DnsSearchDomain * first)154 bool dns_search_domain_unlink_marked(DnsSearchDomain *first) {
155         DnsSearchDomain *next;
156         bool changed;
157 
158         if (!first)
159                 return false;
160 
161         next = first->domains_next;
162 
163         if (first->marked) {
164                 dns_search_domain_unlink(first);
165                 changed = true;
166         } else
167                 changed = false;
168 
169         return dns_search_domain_unlink_marked(next) || changed;
170 }
171 
dns_search_domain_mark_all(DnsSearchDomain * first)172 void dns_search_domain_mark_all(DnsSearchDomain *first) {
173         if (!first)
174                 return;
175 
176         first->marked = true;
177         dns_search_domain_mark_all(first->domains_next);
178 }
179 
dns_search_domain_find(DnsSearchDomain * first,const char * name,DnsSearchDomain ** ret)180 int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret) {
181         int r;
182 
183         assert(name);
184         assert(ret);
185 
186         LIST_FOREACH(domains, d, first) {
187 
188                 r = dns_name_equal(name, d->name);
189                 if (r < 0)
190                         return r;
191                 if (r > 0) {
192                         *ret = d;
193                         return 1;
194                 }
195         }
196 
197         *ret = NULL;
198         return 0;
199 }
200