Coverage Report

Created: 2025-08-03 06:21

/src/dnsmasq/src/domain.c
Line
Count
Source (jump to first uncovered line)
1
/* dnsmasq is Copyright (c) 2000-2025 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 *addrp)
26
501
{
27
501
  char *p;
28
501
  struct cond_domain *c = NULL;
29
501
  int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET;
30
501
  union all_addr addr;
31
  
32
501
  for (c = daemon->synth_domains; c; c = c->next)
33
0
    {
34
0
      int found = 0;
35
0
      char *tail, *pref;
36
      
37
0
      for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
38
0
  {
39
0
    unsigned int c1 = (unsigned char) *pref;
40
0
    unsigned int c2 = (unsigned char) *tail;
41
    
42
0
    if (c1 >= 'A' && c1 <= 'Z')
43
0
      c1 += 'a' - 'A';
44
0
    if (c2 >= 'A' && c2 <= 'Z')
45
0
      c2 += 'a' - 'A';
46
    
47
0
    if (c1 != c2)
48
0
      break;
49
0
  }
50
      
51
0
      if (pref && *pref != 0)
52
0
  continue; /* prefix match fail */
53
54
0
      if (c->indexed)
55
0
  {
56
0
    for (p = tail; *p; p++)
57
0
      {
58
0
        char c = *p;
59
        
60
0
        if (c < '0' || c > '9')
61
0
    break;
62
0
      }
63
    
64
0
    if (*p != '.')
65
0
      continue;
66
    
67
0
    *p = 0;
68
    
69
0
    if (hostname_isequal(c->domain, p+1))
70
0
      {
71
0
        if (prot == AF_INET)
72
0
    {
73
0
      unsigned int index = atoi(tail);
74
75
0
       if (!c->is6 &&
76
0
          index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
77
0
        {
78
0
          addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
79
0
          found = 1;
80
0
        }
81
0
    } 
82
0
        else
83
0
    {
84
0
      u64 index = atoll(tail);
85
      
86
0
      if (c->is6 &&
87
0
          index <= addr6part(&c->end6) - addr6part(&c->start6))
88
0
        {
89
0
          u64 start = addr6part(&c->start6);
90
0
          addr.addr6 = c->start6;
91
0
          setaddr6part(&addr.addr6, start + index);
92
0
          found = 1;
93
0
        }
94
0
    }
95
0
      }
96
0
  }
97
0
      else
98
0
  {
99
    /* NB, must not alter name if we return zero */
100
0
    for (p = tail; *p; p++)
101
0
      {
102
0
        char c = *p;
103
        
104
0
        if ((c >='0' && c <= '9') || c == '-')
105
0
    continue;
106
        
107
0
        if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f'))) 
108
0
    continue;
109
        
110
0
        break;
111
0
      }
112
    
113
0
    if (*p != '.')
114
0
      continue;
115
    
116
0
    *p = 0; 
117
    
118
    /* swap . or : for - */
119
0
    for (p = tail; *p; p++)
120
0
      if (*p == '-')
121
0
        {
122
0
    if (prot == AF_INET)
123
0
      *p = '.';
124
0
    else
125
0
      *p = ':';
126
0
        }
127
    
128
0
    if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, &addr))
129
0
      found = (prot == AF_INET) ? match_domain(addr.addr4, c) : match_domain6(&addr.addr6, c);
130
0
  }
131
      
132
      /* restore name */
133
0
      for (p = tail; *p; p++)
134
0
  if (*p == '.' || *p == ':')
135
0
    *p = '-';
136
      
137
0
      *p = '.';
138
      
139
      
140
0
      if (found)
141
0
  {
142
0
    if (addrp)
143
0
      *addrp = addr;
144
    
145
0
    return 1;
146
0
  }
147
0
    }
148
  
149
501
  return 0;
150
501
}
151
152
153
int is_rev_synth(int flag, union all_addr *addr, char *name)
154
0
{
155
0
   struct cond_domain *c;
156
157
0
   if (flag & F_IPV4 && (c = search_domain(addr->addr4, daemon->synth_domains))) 
158
0
     {
159
0
       char *p;
160
       
161
0
       *name = 0;
162
0
       if (c->indexed)
163
0
   {
164
0
     unsigned int index = ntohl(addr->addr4.s_addr) - ntohl(c->start.s_addr);
165
0
     snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
166
0
   }
167
0
       else
168
0
   {
169
0
     if (c->prefix)
170
0
       strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
171
       
172
0
           inet_ntop(AF_INET, &addr->addr4, name + strlen(name), ADDRSTRLEN);
173
0
     for (p = name; *p; p++)
174
0
       if (*p == '.')
175
0
         *p = '-';
176
0
   }
177
       
178
0
       strncat(name, ".", MAXDNAME);
179
0
       strncat(name, c->domain, MAXDNAME);
180
181
0
       return 1;
182
0
     }
183
184
0
   if ((flag & F_IPV6) && (c = search_domain6(&addr->addr6, daemon->synth_domains))) 
185
0
     {
186
0
       *name = 0;
187
188
0
       if (c->indexed)
189
0
   {
190
0
     u64 index = addr6part(&addr->addr6) - addr6part(&c->start6);
191
0
     snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
192
0
   }
193
0
       else
194
0
   {
195
0
     int i;
196
0
     char frag[6];
197
198
0
     if (c->prefix)
199
0
       strncpy(name, c->prefix, MAXDNAME);
200
     
201
0
     for (i = 0; i < 16; i += 2)
202
0
       {
203
0
         sprintf(frag, "%s%02x%02x",  i == 0 ? "" : "-", addr->addr6.s6_addr[i], addr->addr6.s6_addr[i+1]);
204
0
         strncat(name, frag, MAXDNAME);
205
0
       }
206
0
   }
207
208
0
       strncat(name, ".", MAXDNAME);
209
0
       strncat(name, c->domain, MAXDNAME);
210
       
211
0
       return 1;
212
0
     }
213
   
214
0
   return 0;
215
0
}
216
217
218
static int match_domain(struct in_addr addr, struct cond_domain *c)
219
0
{
220
0
  if (c->interface)
221
0
    {
222
0
      struct addrlist *al;
223
0
      for (al = c->al; al; al = al->next)
224
0
  if (!(al->flags & ADDRLIST_IPV6) &&
225
0
      is_same_net_prefix(addr, al->addr.addr4, al->prefixlen))
226
0
    return 1;
227
0
    }
228
0
  else if (!c->is6 &&
229
0
     ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
230
0
     ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
231
0
    return 1;
232
233
0
  return 0;
234
0
}
235
236
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
237
0
{
238
0
  for (; c; c = c->next)
239
0
    if (match_domain(addr, c))
240
0
      return c;
241
  
242
0
  return NULL;
243
0
}
244
245
char *get_domain(struct in_addr addr)
246
0
{
247
0
  struct cond_domain *c;
248
249
0
  if ((c = search_domain(addr, daemon->cond_domain)))
250
0
    return c->domain;
251
252
0
  return daemon->domain_suffix;
253
0
} 
254
255
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
256
0
{
257
    
258
  /* subnet from interface address. */
259
0
  if (c->interface)
260
0
    {
261
0
      struct addrlist *al;
262
0
      for (al = c->al; al; al = al->next)
263
0
  if (al->flags & ADDRLIST_IPV6 &&
264
0
      is_same_net6(addr, &al->addr.addr6, al->prefixlen))
265
0
    return 1;
266
0
    }
267
0
  else if (c->is6)
268
0
    {
269
0
      if (c->prefixlen >= 64)
270
0
  {
271
0
    u64 addrpart = addr6part(addr);
272
0
    if (is_same_net6(addr, &c->start6, 64) &&
273
0
        addrpart >= addr6part(&c->start6) &&
274
0
        addrpart <= addr6part(&c->end6))
275
0
      return 1;
276
0
  }
277
0
      else if (is_same_net6(addr, &c->start6, c->prefixlen))
278
0
  return 1;
279
0
    }
280
    
281
0
  return 0;
282
0
}
283
284
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
285
0
{
286
0
  for (; c; c = c->next)
287
0
    if (match_domain6(addr, c))
288
0
      return c;
289
  
290
0
  return NULL;
291
0
}
292
293
char *get_domain6(struct in6_addr *addr)
294
0
{
295
0
  struct cond_domain *c;
296
297
0
  if (addr && (c = search_domain6(addr, daemon->cond_domain)))
298
0
    return c->domain;
299
300
0
  return daemon->domain_suffix;
301
0
}