]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/network.c
1 /* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
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.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
13 /* Author's email: simon@thekelleys.org.uk */
17 static struct irec
*add_iface(struct daemon
*daemon
, struct irec
*list
, char *name
, union mysockaddr
*addr
)
23 if (daemon
->if_except
)
24 for (tmp
= daemon
->if_except
; tmp
; tmp
= tmp
->next
)
25 if (tmp
->name
&& strcmp(tmp
->name
, name
) == 0)
27 /* record address of named interfaces, for TCP access control */
32 /* we may need to check the whitelist */
33 if (daemon
->if_names
|| daemon
->if_addrs
)
37 for (tmp
= daemon
->if_names
; tmp
; tmp
= tmp
->next
)
38 if (tmp
->name
&& (strcmp(tmp
->name
, name
) == 0))
41 found
= tmp
->used
= 1;
44 for (tmp
= daemon
->if_addrs
; tmp
; tmp
= tmp
->next
)
45 if (sockaddr_isequal(&tmp
->addr
, addr
))
46 found
= tmp
->used
= 1;
52 /* check whether the interface IP has been added already
53 it is possible to have multiple interfaces with the same address */
54 for (iface
= list
; iface
; iface
= iface
->next
)
55 if (sockaddr_isequal(&iface
->addr
, addr
))
60 /* If OK, add it to the head of the list */
61 iface
= safe_malloc(sizeof(struct irec
));
68 struct irec
*enumerate_interfaces(struct daemon
*daemon
)
70 struct irec
*iface
= NULL
;
72 struct ifreq
*ifr
= NULL
;
75 int len
= 20 * sizeof(struct ifreq
);
76 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
79 die ("cannot create socket to enumerate interfaces: %s", NULL
);
83 buf
= safe_malloc(len
);
87 if (ioctl(fd
, SIOCGIFCONF
, &ifc
) < 0)
89 if (errno
!= EINVAL
|| lastlen
!= 0)
90 die ("ioctl error while enumerating interfaces: %s", NULL
);
94 if (ifc
.ifc_len
== lastlen
)
95 break; /* got a big enough buffer now */
96 lastlen
= ifc
.ifc_len
;
98 len
+= 10*sizeof(struct ifreq
);
102 for (ptr
= buf
; ptr
< buf
+ len
; )
104 union mysockaddr addr
;
105 #ifdef HAVE_SOCKADDR_SA_LEN
106 /* subsequent entries may not be aligned, so copy into
107 an aligned buffer to avoid nasty complaints about
108 unaligned accesses. */
109 int ifr_len
= ((struct ifreq
*)ptr
)->ifr_addr
.sa_len
+ IF_NAMESIZE
;
110 if (!(ifr
= realloc(ifr
, ifr_len
)))
111 die("cannot allocate buffer", NULL
);
113 memcpy(ifr
, ptr
, ifr_len
);
116 ifr
= (struct ifreq
*)ptr
;
117 ptr
+= sizeof(struct ifreq
);
120 /* copy address since getting flags overwrites */
121 if (ifr
->ifr_addr
.sa_family
== AF_INET
)
123 addr
.in
= *((struct sockaddr_in
*) &ifr
->ifr_addr
);
124 addr
.in
.sin_port
= htons(daemon
->port
);
127 else if (ifr
->ifr_addr
.sa_family
== AF_INET6
)
129 #ifdef HAVE_BROKEN_SOCKADDR_IN6
130 addr
.in6
= *((struct my_sockaddr_in6
*) &ifr
->ifr_addr
);
132 addr
.in6
= *((struct sockaddr_in6
*) &ifr
->ifr_addr
);
134 addr
.in6
.sin6_port
= htons(daemon
->port
);
135 addr
.in6
.sin6_flowinfo
= htonl(0);
139 continue; /* unknown address family */
141 if (ioctl(fd
, SIOCGIFFLAGS
, ifr
) < 0)
142 die("ioctl error getting interface flags: %m", NULL
);
144 /* If we are restricting the set of interfaces to use, make
145 sure that loopback interfaces are in that set. */
146 if (daemon
->if_names
&& (ifr
->ifr_flags
& IFF_LOOPBACK
))
149 for (lo
= daemon
->if_names
; lo
; lo
= lo
->next
)
150 if (lo
->name
&& strcmp(lo
->name
, ifr
->ifr_name
) == 0)
157 lo
= safe_malloc(sizeof(struct iname
));
158 lo
->name
= safe_string_alloc(ifr
->ifr_name
);
159 lo
->isloop
= lo
->used
= 1;
160 lo
->next
= daemon
->if_names
;
161 daemon
->if_names
= lo
;
165 iface
= add_iface(daemon
, iface
, ifr
->ifr_name
, &addr
);
167 #if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
168 /* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
169 /* This code snarfed from net-tools 1.60 and certainly linux specific, though
170 it shouldn't break on other Unices, and their SIOGIFCONF might work. */
172 FILE *f
= fopen(IP6INTERFACES
, "r");
174 union mysockaddr addr6
;
178 unsigned int plen
, scope
, flags
, if_idx
;
179 char devname
[20], addrstring
[32];
181 while (fscanf(f
, "%32s %02x %02x %02x %02x %20s\n",
182 addrstring
, &if_idx
, &plen
, &scope
, &flags
, devname
) != EOF
)
184 if (strcmp(devname
, ifr
->ifr_name
) == 0)
187 unsigned char *addr6p
= (unsigned char *) &addr6
.in6
.sin6_addr
;
188 memset(&addr6
, 0, sizeof(addr6
));
189 addr6
.sa
.sa_family
= AF_INET6
;
193 sscanf(addrstring
+i
+i
, "%02x", &byte
);
196 addr6
.in6
.sin6_port
= htons(daemon
->port
);
197 addr6
.in6
.sin6_flowinfo
= htonl(0);
198 addr6
.in6
.sin6_scope_id
= htonl(scope
);
209 iface
= add_iface(daemon
, iface
, ifr
->ifr_name
, &addr6
);
216 #ifdef HAVE_SOCKADDR_SA_LEN
226 static int create_ipv6_listener(struct listener
**link
, int port
)
228 union mysockaddr addr
;
229 int tcpfd
, fd
, flags
, save
;
233 addr
.in6
.sin6_family
= AF_INET6
;
234 addr
.in6
.sin6_addr
= in6addr_any
;
235 addr
.in6
.sin6_port
= htons(port
);
236 addr
.in6
.sin6_flowinfo
= htonl(0);
237 #ifdef HAVE_SOCKADDR_SA_LEN
238 addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
241 /* No error of the kernel doesn't support IPv6 */
242 if ((fd
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1)
243 return (errno
== EPROTONOSUPPORT
||
244 errno
== EAFNOSUPPORT
||
247 if ((tcpfd
= socket(AF_INET6
, SOCK_STREAM
, 0)) == -1)
255 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
256 setsockopt(tcpfd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
257 setsockopt(fd
, IPV6_LEVEL
, IPV6_V6ONLY
, &opt
, sizeof(opt
)) == -1 ||
258 setsockopt(tcpfd
, IPV6_LEVEL
, IPV6_V6ONLY
, &opt
, sizeof(opt
)) == -1 ||
259 (flags
= fcntl(fd
, F_GETFL
, 0)) == -1 ||
260 fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
261 (flags
= fcntl(tcpfd
, F_GETFL
, 0)) == -1 ||
262 fcntl(tcpfd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
263 #ifdef IPV6_RECVPKTINFO
264 setsockopt(fd
, IPV6_LEVEL
, IPV6_RECVPKTINFO
, &opt
, sizeof(opt
)) == -1 ||
266 setsockopt(fd
, IPV6_LEVEL
, IPV6_PKTINFO
, &opt
, sizeof(opt
)) == -1 ||
268 bind(tcpfd
, (struct sockaddr
*)&addr
, sa_len(&addr
)) == -1 ||
269 listen(tcpfd
, 5) == -1 ||
270 bind(fd
, (struct sockaddr
*)&addr
, sa_len(&addr
)) == -1)
279 l
= safe_malloc(sizeof(struct listener
));
282 l
->family
= AF_INET6
;
290 struct listener
*create_wildcard_listeners(int port
)
292 #if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
295 union mysockaddr addr
;
297 struct listener
*l
, *l6
= NULL
;
301 addr
.in
.sin_family
= AF_INET
;
302 addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
303 addr
.in
.sin_port
= htons(port
);
304 #ifdef HAVE_SOCKADDR_SA_LEN
305 addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
308 if ((fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
311 if ((tcpfd
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1)
317 if (setsockopt(tcpfd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
318 bind(tcpfd
, (struct sockaddr
*)&addr
, sa_len(&addr
)) == -1 ||
319 listen(tcpfd
, 5) == -1 ||
320 (flags
= fcntl(tcpfd
, F_GETFL
, 0)) == -1 ||
321 fcntl(tcpfd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
323 !create_ipv6_listener(&l6
, port
) ||
325 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
326 (flags
= fcntl(fd
, F_GETFL
, 0)) == -1 ||
327 fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
328 #if defined(IP_PKTINFO)
329 setsockopt(fd
, SOL_IP
, IP_PKTINFO
, &opt
, sizeof(opt
)) == -1 ||
330 #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
331 setsockopt(fd
, IPPROTO_IP
, IP_RECVDSTADDR
, &opt
, sizeof(opt
)) == -1 ||
332 setsockopt(fd
, IPPROTO_IP
, IP_RECVIF
, &opt
, sizeof(opt
)) == -1 ||
334 bind(fd
, (struct sockaddr
*)&addr
, sa_len(&addr
)) == -1)
341 l
= safe_malloc(sizeof(struct listener
));
352 struct listener
*create_bound_listeners(struct irec
*interfaces
, int port
)
355 struct listener
*listeners
= NULL
;
357 int flags
= port
, opt
= 1;
359 /* Create bound listeners only for IPv4, IPv6 always binds the wildcard */
362 if (!create_ipv6_listener(&listeners
, port
))
363 die("failed to to create listening socket: %s", NULL
);
366 for (iface
= interfaces
;iface
; iface
= iface
->next
)
367 if (iface
->addr
.sa
.sa_family
== AF_INET
)
369 struct listener
*new = safe_malloc(sizeof(struct listener
));
370 new->family
= iface
->addr
.sa
.sa_family
;
371 new->next
= listeners
;
373 if ((new->tcpfd
= socket(iface
->addr
.sa
.sa_family
, SOCK_STREAM
, 0)) == -1 ||
374 (new->fd
= socket(iface
->addr
.sa
.sa_family
, SOCK_DGRAM
, 0)) == -1 ||
375 setsockopt(new->fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
376 setsockopt(new->tcpfd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
)) == -1 ||
377 /* See Stevens 16.6 */
378 (flags
= fcntl(new->tcpfd
, F_GETFL
, 0)) == -1 ||
379 fcntl(new->tcpfd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
380 (flags
= fcntl(new->fd
, F_GETFL
, 0)) == -1 ||
381 fcntl(new->fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1 ||
382 bind(new->tcpfd
, &iface
->addr
.sa
, sa_len(&iface
->addr
)) == -1 ||
383 bind(new->fd
, &iface
->addr
.sa
, sa_len(&iface
->addr
)) == -1 ||
384 listen(new->tcpfd
, 5) == -1)
385 die("failed to to create listening socket: %s", NULL
);
391 struct serverfd
*allocate_sfd(union mysockaddr
*addr
, struct serverfd
**sfds
)
393 struct serverfd
*sfd
;
396 /* may have a suitable one already */
397 for (sfd
= *sfds
; sfd
; sfd
= sfd
->next
)
398 if (sockaddr_isequal(&sfd
->source_addr
, addr
))
401 /* need to make a new one. */
402 errno
= ENOMEM
; /* in case malloc fails. */
403 if (!(sfd
= malloc(sizeof(struct serverfd
))))
406 if ((sfd
->fd
= socket(addr
->sa
.sa_family
, SOCK_DGRAM
, 0)) == -1)
412 if (bind(sfd
->fd
, (struct sockaddr
*)addr
, sa_len(addr
)) == -1 ||
413 (flags
= fcntl(sfd
->fd
, F_GETFL
, 0)) == -1 ||
414 fcntl(sfd
->fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
416 int errsave
= errno
; /* save error from bind. */
423 sfd
->source_addr
= *addr
;
430 void check_servers(struct daemon
*daemon
, struct irec
*interfaces
)
432 char addrbuff
[ADDRSTRLEN
];
434 struct server
*new, *tmp
, *ret
= NULL
;
437 /* forward table rules reference servers, so have to blow them away */
440 daemon
->last_server
= NULL
;
442 for (new = daemon
->servers
; new; new = tmp
)
446 if (!(new->flags
& (SERV_LITERAL_ADDRESS
| SERV_NO_ADDR
)))
449 if (new->addr
.sa
.sa_family
== AF_INET
)
451 inet_ntop(AF_INET
, &new->addr
.in
.sin_addr
, addrbuff
, ADDRSTRLEN
);
452 port
= ntohs(new->addr
.in
.sin_port
);
454 else if (new->addr
.sa
.sa_family
== AF_INET6
)
456 inet_ntop(AF_INET6
, &new->addr
.in6
.sin6_addr
, addrbuff
, ADDRSTRLEN
);
457 port
= ntohs(new->addr
.in6
.sin6_port
);
460 strcpy(addrbuff
, inet_ntoa(new->addr
.in
.sin_addr
));
461 port
= ntohs(new->addr
.in
.sin_port
);
463 for (iface
= interfaces
; iface
; iface
= iface
->next
)
464 if (sockaddr_isequal(&new->addr
, &iface
->addr
))
468 syslog(LOG_WARNING
, "ignoring nameserver %s - local interface", addrbuff
);
473 /* Do we need a socket set? */
474 if (!new->sfd
&& !(new->sfd
= allocate_sfd(&new->source_addr
, &daemon
->sfds
)))
477 "ignoring nameserver %s - cannot make/bind socket: %m", addrbuff
);
483 /* reverse order - gets it right. */
487 if (new->flags
& (SERV_HAS_DOMAIN
| SERV_FOR_NODOTS
))
490 if (new->flags
& SERV_HAS_DOMAIN
)
491 s1
= "domain", s2
= new->domain
;
493 s1
= "unqualified", s2
= "domains";
495 if (new->flags
& SERV_NO_ADDR
)
496 syslog(LOG_INFO
, "using local addresses only for %s %s", s1
, s2
);
497 else if (!(new->flags
& SERV_LITERAL_ADDRESS
))
498 syslog(LOG_INFO
, "using nameserver %s#%d for %s %s", addrbuff
, port
, s1
, s2
);
501 syslog(LOG_INFO
, "using nameserver %s#%d", addrbuff
, port
);
504 daemon
->servers
= ret
;
507 void reload_servers(char *fname
, struct daemon
*daemon
)
511 struct server
*old_servers
= NULL
;
512 struct server
*new_servers
= NULL
;
513 struct server
*serv
= daemon
->servers
;
515 /* move old servers to free list - we can reuse the memory
516 and not risk malloc if there are the same or fewer new servers.
517 Servers which were specced on the command line go to the new list. */
520 struct server
*tmp
= serv
->next
;
521 if (serv
->flags
& SERV_FROM_RESOLV
)
523 serv
->next
= old_servers
;
528 serv
->next
= new_servers
;
534 /* buff happens to be NAXDNAME long... */
535 f
= fopen(fname
, "r");
538 syslog(LOG_ERR
, "failed to read %s: %m", fname
);
542 syslog(LOG_INFO
, "reading %s", fname
);
543 while ((line
= fgets(daemon
->namebuff
, MAXDNAME
, f
)))
545 union mysockaddr addr
, source_addr
;
546 char *token
= strtok(line
, " \t\n\r");
549 if (!token
|| strcmp(token
, "nameserver") != 0)
551 if (!(token
= strtok(NULL
, " \t\n\r")))
555 if (inet_pton(AF_INET
, token
, &addr
.in
.sin_addr
))
557 if ((addr
.in
.sin_addr
.s_addr
= inet_addr(token
)) != (in_addr_t
) -1)
560 #ifdef HAVE_SOCKADDR_SA_LEN
561 source_addr
.in
.sin_len
= addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
563 source_addr
.in
.sin_family
= addr
.in
.sin_family
= AF_INET
;
564 addr
.in
.sin_port
= htons(NAMESERVER_PORT
);
565 source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
566 source_addr
.in
.sin_port
= htons(daemon
->query_port
);
569 else if (inet_pton(AF_INET6
, token
, &addr
.in6
.sin6_addr
))
571 #ifdef HAVE_SOCKADDR_SA_LEN
572 source_addr
.in6
.sin6_len
= addr
.in6
.sin6_len
= sizeof(struct sockaddr_in6
);
574 source_addr
.in6
.sin6_family
= addr
.in6
.sin6_family
= AF_INET6
;
575 addr
.in6
.sin6_port
= htons(NAMESERVER_PORT
);
576 source_addr
.in6
.sin6_flowinfo
= addr
.in6
.sin6_flowinfo
= htonl(0);
577 source_addr
.in6
.sin6_addr
= in6addr_any
;
578 source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
587 old_servers
= old_servers
->next
;
589 else if (!(serv
= malloc(sizeof (struct server
))))
592 /* this list is reverse ordered:
593 it gets reversed again in check_servers */
594 serv
->next
= new_servers
;
597 serv
->source_addr
= source_addr
;
600 serv
->flags
= SERV_FROM_RESOLV
;
606 /* Free any memory not used. */
609 struct server
*tmp
= old_servers
->next
;
614 daemon
->servers
= new_servers
;