Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / domain.c
1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; version 2 dated June, 1991, or
6    (at your option) version 3 dated 29 June, 2007.
7  
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12      
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "dnsmasq.h"
18
19
20 static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
21 static int match_domain(struct in_addr addr, struct cond_domain *c);
22 static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
23 static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
24
25 int is_name_synthetic(int flags, char *name, union all_addr *addr)
26 {
27   char *p;
28   struct cond_domain *c = NULL;
29   int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET;
30
31   for (c = daemon->synth_domains; c; c = c->next)
32     {
33       int found = 0;
34       char *tail, *pref;
35       
36       for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
37         {
38           unsigned int c1 = (unsigned char) *pref;
39           unsigned int c2 = (unsigned char) *tail;
40           
41           if (c1 >= 'A' && c1 <= 'Z')
42             c1 += 'a' - 'A';
43           if (c2 >= 'A' && c2 <= 'Z')
44             c2 += 'a' - 'A';
45           
46           if (c1 != c2)
47             break;
48         }
49       
50       if (pref && *pref != 0)
51         continue; /* prefix match fail */
52
53       if (c->indexed)
54         {
55           for (p = tail; *p; p++)
56             {
57               char c = *p;
58               
59               if (c < '0' || c > '9')
60                 break;
61             }
62           
63           if (*p != '.')
64             continue;
65           
66           *p = 0;
67           
68           if (hostname_isequal(c->domain, p+1))
69             {
70               if (prot == AF_INET)
71                 {
72                   unsigned int index = atoi(tail);
73
74                    if (!c->is6 &&
75                       index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
76                     {
77                       addr->addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
78                       found = 1;
79                     }
80                 } 
81               else
82                 {
83                   u64 index = atoll(tail);
84                   
85                   if (c->is6 &&
86                       index <= addr6part(&c->end6) - addr6part(&c->start6))
87                     {
88                       u64 start = addr6part(&c->start6);
89                       addr->addr6 = c->start6;
90                       setaddr6part(&addr->addr6, start + index);
91                       found = 1;
92                     }
93                 }
94             }
95         }
96       else
97         {
98           /* NB, must not alter name if we return zero */
99           for (p = tail; *p; p++)
100             {
101               char c = *p;
102               
103               if ((c >='0' && c <= '9') || c == '-')
104                 continue;
105               
106               if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) 
107                 continue;
108               
109               break;
110             }
111           
112           if (*p != '.')
113             continue;
114           
115           *p = 0;       
116           
117           if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
118             {
119               /* special hack for v4-mapped. */
120               memcpy(tail, "::ffff:", 7);
121               for (p = tail + 7; *p; p++)
122                 if (*p == '-')
123                   *p = '.';
124             }
125           else
126             {
127               /* swap . or : for - */
128               for (p = tail; *p; p++)
129                 if (*p == '-')
130                   {
131                     if (prot == AF_INET)
132                       *p = '.';
133                     else
134                       *p = ':';
135                   }
136             }
137           
138           if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
139             found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
140         }
141       
142       /* restore name */
143       for (p = tail; *p; p++)
144         if (*p == '.' || *p == ':')
145           *p = '-';
146       
147       *p = '.';
148       
149       
150       if (found)
151         return 1;
152     }
153   
154   return 0;
155 }
156
157
158 int is_rev_synth(int flag, union all_addr *addr, char *name)
159 {
160    struct cond_domain *c;
161
162    if (flag & F_IPV4 && (c = search_domain(addr->addr4, daemon->synth_domains))) 
163      {
164        char *p;
165        
166        *name = 0;
167        if (c->indexed)
168          {
169            unsigned int index = ntohl(addr->addr4.s_addr) - ntohl(c->start.s_addr);
170            snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
171          }
172        else
173          {
174            if (c->prefix)
175              strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
176        
177            inet_ntop(AF_INET, &addr->addr4, name + strlen(name), ADDRSTRLEN);
178            for (p = name; *p; p++)
179              if (*p == '.')
180                *p = '-';
181          }
182        
183        strncat(name, ".", MAXDNAME);
184        strncat(name, c->domain, MAXDNAME);
185
186        return 1;
187      }
188
189    if ((flag & F_IPV6) && (c = search_domain6(&addr->addr6, daemon->synth_domains))) 
190      {
191        char *p;
192        
193        *name = 0;
194        if (c->indexed)
195          {
196            u64 index = addr6part(&addr->addr6) - addr6part(&c->start6);
197            snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
198          }
199        else
200          {
201            if (c->prefix)
202              strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
203        
204            inet_ntop(AF_INET6, &addr->addr6, name + strlen(name), ADDRSTRLEN);
205
206            /* IPv6 presentation address can start with ":", but valid domain names
207               cannot start with "-" so prepend a zero in that case. */
208            if (!c->prefix && *name == ':')
209              {
210                *name = '0';
211                inet_ntop(AF_INET6, &addr->addr6, name+1, ADDRSTRLEN);
212              }
213            
214            /* V4-mapped have periods.... */
215            for (p = name; *p; p++)
216              if (*p == ':' || *p == '.')
217                *p = '-';
218            
219          }
220
221        strncat(name, ".", MAXDNAME);
222        strncat(name, c->domain, MAXDNAME);
223        
224        return 1;
225      }
226    
227    return 0;
228 }
229
230
231 static int match_domain(struct in_addr addr, struct cond_domain *c)
232 {
233   if (c->interface)
234     {
235       struct addrlist *al;
236       for (al = c->al; al; al = al->next)
237         if (!(al->flags & ADDRLIST_IPV6) &&
238             is_same_net_prefix(addr, al->addr.addr4, al->prefixlen))
239           return 1;
240     }
241   else if (!c->is6 &&
242            ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
243            ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
244     return 1;
245
246   return 0;
247 }
248
249 static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
250 {
251   for (; c; c = c->next)
252     if (match_domain(addr, c))
253       return c;
254   
255   return NULL;
256 }
257
258 char *get_domain(struct in_addr addr)
259 {
260   struct cond_domain *c;
261
262   if ((c = search_domain(addr, daemon->cond_domain)))
263     return c->domain;
264
265   return daemon->domain_suffix;
266
267
268 static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
269 {
270     
271   /* subnet from interface address. */
272   if (c->interface)
273     {
274       struct addrlist *al;
275       for (al = c->al; al; al = al->next)
276         if (al->flags & ADDRLIST_IPV6 &&
277             is_same_net6(addr, &al->addr.addr6, al->prefixlen))
278           return 1;
279     }
280   else if (c->is6)
281     {
282       if (c->prefixlen >= 64)
283         {
284           u64 addrpart = addr6part(addr);
285           if (is_same_net6(addr, &c->start6, 64) &&
286               addrpart >= addr6part(&c->start6) &&
287               addrpart <= addr6part(&c->end6))
288             return 1;
289         }
290       else if (is_same_net6(addr, &c->start6, c->prefixlen))
291         return 1;
292     }
293     
294   return 0;
295 }
296
297 static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
298 {
299   for (; c; c = c->next)
300     if (match_domain6(addr, c))
301       return c;
302   
303   return NULL;
304 }
305
306 char *get_domain6(struct in6_addr *addr)
307 {
308   struct cond_domain *c;
309
310   if (addr && (c = search_domain6(addr, daemon->cond_domain)))
311     return c->domain;
312
313   return daemon->domain_suffix;
314