| /* SPDX-License-Identifier: LGPL-2.1+ */ |
| /*** |
| This file is part of systemd. |
| |
| Copyright 2015 Lennart Poettering |
| |
| systemd is free software; you can redistribute it and/or modify it |
| under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2.1 of the License, or |
| (at your option) any later version. |
| |
| systemd is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with systemd; If not, see <http://www.gnu.org/licenses/>. |
| ***/ |
| |
| #include "alloc-util.h" |
| #include "dns-domain.h" |
| #include "resolved-dns-search-domain.h" |
| |
| int dns_search_domain_new( |
| Manager *m, |
| DnsSearchDomain **ret, |
| DnsSearchDomainType type, |
| Link *l, |
| const char *name) { |
| |
| _cleanup_free_ char *normalized = NULL; |
| DnsSearchDomain *d; |
| int r; |
| |
| assert(m); |
| assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l); |
| assert(name); |
| |
| r = dns_name_normalize(name, &normalized); |
| if (r < 0) |
| return r; |
| |
| if (l) { |
| if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX) |
| return -E2BIG; |
| } else { |
| if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX) |
| return -E2BIG; |
| } |
| |
| d = new0(DnsSearchDomain, 1); |
| if (!d) |
| return -ENOMEM; |
| |
| d->n_ref = 1; |
| d->manager = m; |
| d->type = type; |
| d->name = normalized; |
| normalized = NULL; |
| |
| switch (type) { |
| |
| case DNS_SEARCH_DOMAIN_LINK: |
| d->link = l; |
| LIST_APPEND(domains, l->search_domains, d); |
| l->n_search_domains++; |
| break; |
| |
| case DNS_SERVER_SYSTEM: |
| LIST_APPEND(domains, m->search_domains, d); |
| m->n_search_domains++; |
| break; |
| |
| default: |
| assert_not_reached("Unknown search domain type"); |
| } |
| |
| d->linked = true; |
| |
| if (ret) |
| *ret = d; |
| |
| return 0; |
| } |
| |
| DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d) { |
| if (!d) |
| return NULL; |
| |
| assert(d->n_ref > 0); |
| d->n_ref++; |
| |
| return d; |
| } |
| |
| DnsSearchDomain* dns_search_domain_unref(DnsSearchDomain *d) { |
| if (!d) |
| return NULL; |
| |
| assert(d->n_ref > 0); |
| d->n_ref--; |
| |
| if (d->n_ref > 0) |
| return NULL; |
| |
| free(d->name); |
| return mfree(d); |
| } |
| |
| void dns_search_domain_unlink(DnsSearchDomain *d) { |
| assert(d); |
| assert(d->manager); |
| |
| if (!d->linked) |
| return; |
| |
| switch (d->type) { |
| |
| case DNS_SEARCH_DOMAIN_LINK: |
| assert(d->link); |
| assert(d->link->n_search_domains > 0); |
| LIST_REMOVE(domains, d->link->search_domains, d); |
| d->link->n_search_domains--; |
| break; |
| |
| case DNS_SEARCH_DOMAIN_SYSTEM: |
| assert(d->manager->n_search_domains > 0); |
| LIST_REMOVE(domains, d->manager->search_domains, d); |
| d->manager->n_search_domains--; |
| break; |
| } |
| |
| d->linked = false; |
| |
| dns_search_domain_unref(d); |
| } |
| |
| void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) { |
| DnsSearchDomain *tail; |
| |
| assert(d); |
| |
| if (!d->marked) |
| return; |
| |
| d->marked = false; |
| |
| if (!d->linked || !d->domains_next) |
| return; |
| |
| switch (d->type) { |
| |
| case DNS_SEARCH_DOMAIN_LINK: |
| assert(d->link); |
| LIST_FIND_TAIL(domains, d, tail); |
| LIST_REMOVE(domains, d->link->search_domains, d); |
| LIST_INSERT_AFTER(domains, d->link->search_domains, tail, d); |
| break; |
| |
| case DNS_SEARCH_DOMAIN_SYSTEM: |
| LIST_FIND_TAIL(domains, d, tail); |
| LIST_REMOVE(domains, d->manager->search_domains, d); |
| LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d); |
| break; |
| |
| default: |
| assert_not_reached("Unknown search domain type"); |
| } |
| } |
| |
| void dns_search_domain_unlink_all(DnsSearchDomain *first) { |
| DnsSearchDomain *next; |
| |
| if (!first) |
| return; |
| |
| next = first->domains_next; |
| dns_search_domain_unlink(first); |
| |
| dns_search_domain_unlink_all(next); |
| } |
| |
| void dns_search_domain_unlink_marked(DnsSearchDomain *first) { |
| DnsSearchDomain *next; |
| |
| if (!first) |
| return; |
| |
| next = first->domains_next; |
| |
| if (first->marked) |
| dns_search_domain_unlink(first); |
| |
| dns_search_domain_unlink_marked(next); |
| } |
| |
| void dns_search_domain_mark_all(DnsSearchDomain *first) { |
| if (!first) |
| return; |
| |
| first->marked = true; |
| dns_search_domain_mark_all(first->domains_next); |
| } |
| |
| int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret) { |
| DnsSearchDomain *d; |
| int r; |
| |
| assert(name); |
| assert(ret); |
| |
| LIST_FOREACH(domains, d, first) { |
| |
| r = dns_name_equal(name, d->name); |
| if (r < 0) |
| return r; |
| if (r > 0) { |
| *ret = d; |
| return 1; |
| } |
| } |
| |
| *ret = NULL; |
| return 0; |
| } |