]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dhcp-common.c
1 /* dnsmasq is Copyright (c) 2000-2012 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, or
6 (at your option) version 3 dated 29 June, 2007.
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.
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/>.
21 void dhcp_common_init(void)
23 /* These each hold a DHCP option max size 255
24 and get a terminating zero added */
25 daemon
->dhcp_buff
= safe_malloc(256);
26 daemon
->dhcp_buff2
= safe_malloc(256);
27 daemon
->dhcp_buff3
= safe_malloc(256);
29 /* dhcp_packet is used by v4 and v6, outpacket only by v6
30 sizeof(struct dhcp_packet) is as good an initial size as any,
32 expand_buf(&daemon
->dhcp_packet
, sizeof(struct dhcp_packet
));
35 expand_buf(&daemon
->outpacket
, sizeof(struct dhcp_packet
));
39 ssize_t
recv_dhcp_packet(int fd
, struct msghdr
*msg
)
46 while ((sz
= recvmsg(fd
, msg
, MSG_PEEK
| MSG_TRUNC
)) == -1 && errno
== EINTR
);
51 if (!(msg
->msg_flags
& MSG_TRUNC
))
54 /* Very new Linux kernels return the actual size needed,
55 older ones always return truncated size */
56 if ((size_t)sz
== msg
->msg_iov
->iov_len
)
58 if (!expand_buf(msg
->msg_iov
, sz
+ 100))
63 expand_buf(msg
->msg_iov
, sz
);
68 while ((sz
= recvmsg(fd
, msg
, 0)) == -1 && errno
== EINTR
);
70 return (msg
->msg_flags
& MSG_TRUNC
) ? -1 : sz
;
73 struct dhcp_netid
*run_tag_if(struct dhcp_netid
*tags
)
76 struct dhcp_netid_list
*list
;
78 for (exprs
= daemon
->tag_if
; exprs
; exprs
= exprs
->next
)
79 if (match_netid(exprs
->tag
, tags
, 1))
80 for (list
= exprs
->set
; list
; list
= list
->next
)
82 list
->list
->next
= tags
;
90 struct dhcp_netid
*option_filter(struct dhcp_netid
*tags
, struct dhcp_netid
*context_tags
, struct dhcp_opt
*opts
)
92 struct dhcp_netid
*tagif
= run_tag_if(tags
);
95 /* flag options which are valid with the current tag set (sans context tags) */
96 for (opt
= opts
; opt
; opt
= opt
->next
)
98 opt
->flags
&= ~DHOPT_TAGOK
;
99 if (!(opt
->flags
& (DHOPT_ENCAPSULATE
| DHOPT_VENDOR
| DHOPT_RFC3925
)) &&
100 match_netid(opt
->netid
, tagif
, 0))
101 opt
->flags
|= DHOPT_TAGOK
;
104 /* now flag options which are valid, including the context tags,
105 otherwise valid options are inhibited if we found a higher priority one above */
108 struct dhcp_netid
*last_tag
;
110 for (last_tag
= context_tags
; last_tag
->next
; last_tag
= last_tag
->next
);
111 last_tag
->next
= tags
;
112 tagif
= run_tag_if(context_tags
);
114 for (opt
= opts
; opt
; opt
= opt
->next
)
115 if (!(opt
->flags
& (DHOPT_ENCAPSULATE
| DHOPT_VENDOR
| DHOPT_RFC3925
| DHOPT_TAGOK
)) &&
116 match_netid(opt
->netid
, tagif
, 0))
118 struct dhcp_opt
*tmp
;
119 for (tmp
= opts
; tmp
; tmp
= tmp
->next
)
120 if (tmp
->opt
== opt
->opt
&& opt
->netid
&& (tmp
->flags
& DHOPT_TAGOK
))
123 opt
->flags
|= DHOPT_TAGOK
;
127 /* now flag untagged options which are not overridden by tagged ones */
128 for (opt
= opts
; opt
; opt
= opt
->next
)
129 if (!(opt
->flags
& (DHOPT_ENCAPSULATE
| DHOPT_VENDOR
| DHOPT_RFC3925
| DHOPT_TAGOK
)) && !opt
->netid
)
131 struct dhcp_opt
*tmp
;
132 for (tmp
= opts
; tmp
; tmp
= tmp
->next
)
133 if (tmp
->opt
== opt
->opt
&& (tmp
->flags
& DHOPT_TAGOK
))
136 opt
->flags
|= DHOPT_TAGOK
;
137 else if (!tmp
->netid
)
138 my_syslog(MS_DHCP
| LOG_WARNING
, _("Ignoring duplicate dhcp-option %d"), tmp
->opt
);
144 /* Is every member of check matched by a member of pool?
145 If tagnotneeded, untagged is OK */
146 int match_netid(struct dhcp_netid
*check
, struct dhcp_netid
*pool
, int tagnotneeded
)
148 struct dhcp_netid
*tmp1
;
150 if (!check
&& !tagnotneeded
)
153 for (; check
; check
= check
->next
)
155 /* '#' for not is for backwards compat. */
156 if (check
->net
[0] != '!' && check
->net
[0] != '#')
158 for (tmp1
= pool
; tmp1
; tmp1
= tmp1
->next
)
159 if (strcmp(check
->net
, tmp1
->net
) == 0)
165 for (tmp1
= pool
; tmp1
; tmp1
= tmp1
->next
)
166 if (strcmp((check
->net
)+1, tmp1
->net
) == 0)
172 /* return domain or NULL if none. */
173 char *strip_hostname(char *hostname
)
175 char *dot
= strchr(hostname
, '.');
180 *dot
= 0; /* truncate */
181 if (strlen(dot
+1) != 0)
187 void log_tags(struct dhcp_netid
*netid
, u32 xid
)
189 if (netid
&& option_bool(OPT_LOG_OPTS
))
191 char *s
= daemon
->namebuff
;
192 for (*s
= 0; netid
; netid
= netid
->next
)
195 struct dhcp_netid
*n
;
197 for (n
= netid
->next
; n
; n
= n
->next
)
198 if (strcmp(netid
->net
, n
->net
) == 0)
203 strncat (s
, netid
->net
, (MAXDNAME
-1) - strlen(s
));
205 strncat (s
, ", ", (MAXDNAME
-1) - strlen(s
));
208 my_syslog(MS_DHCP
| LOG_INFO
, _("%u tags: %s"), xid
, s
);
212 int match_bytes(struct dhcp_opt
*o
, unsigned char *p
, int len
)
222 if (o
->flags
& DHOPT_HEX
)
224 if (memcmp_masked(o
->val
, p
, o
->len
, o
->u
.wildcard_mask
))
228 for (i
= 0; i
<= (len
- o
->len
); )
230 if (memcmp(o
->val
, p
+ i
, o
->len
) == 0)
233 if (o
->flags
& DHOPT_STRING
)
242 void check_dhcp_hosts(int fatal
)
244 /* If the same IP appears in more than one host config, then DISCOVER
245 for one of the hosts will get the address, but REQUEST will be NAKed,
246 since the address is reserved by the other one -> protocol loop.
247 Also check that FQDNs match the domain we are using. */
249 struct dhcp_config
*configs
, *cp
;
251 for (configs
= daemon
->dhcp_conf
; configs
; configs
= configs
->next
)
255 if ((configs
->flags
& DHOPT_BANK
) || fatal
)
257 for (cp
= configs
->next
; cp
; cp
= cp
->next
)
258 if ((configs
->flags
& cp
->flags
& CONFIG_ADDR
) && configs
->addr
.s_addr
== cp
->addr
.s_addr
)
261 die(_("duplicate IP address %s in dhcp-config directive."),
262 inet_ntoa(cp
->addr
), EC_BADCONF
);
264 my_syslog(MS_DHCP
| LOG_ERR
, _("duplicate IP address %s in %s."),
265 inet_ntoa(cp
->addr
), daemon
->dhcp_hosts_file
);
266 configs
->flags
&= ~CONFIG_ADDR
;
269 /* split off domain part */
270 if ((configs
->flags
& CONFIG_NAME
) && (domain
= strip_hostname(configs
->hostname
)))
271 configs
->domain
= domain
;
276 void dhcp_update_configs(struct dhcp_config
*configs
)
278 /* Some people like to keep all static IP addresses in /etc/hosts.
279 This goes through /etc/hosts and sets static addresses for any DHCP config
280 records which don't have an address and whose name matches.
281 We take care to maintain the invariant that any IP address can appear
282 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
283 restore the status-quo ante first. */
285 struct dhcp_config
*config
;
289 for (config
= configs
; config
; config
= config
->next
)
290 if (config
->flags
& CONFIG_ADDR_HOSTS
)
291 config
->flags
&= ~(CONFIG_ADDR
| CONFIG_ADDR6
| CONFIG_ADDR_HOSTS
);
297 if (daemon
->port
!= 0)
298 for (config
= configs
; config
; config
= config
->next
)
300 int conflags
= CONFIG_ADDR
;
301 int cacheflags
= F_IPV4
;
304 if (prot
== AF_INET6
)
306 conflags
= CONFIG_ADDR6
;
310 if (!(config
->flags
& conflags
) &&
311 (config
->flags
& CONFIG_NAME
) &&
312 (crec
= cache_find_by_name(NULL
, config
->hostname
, 0, cacheflags
)) &&
313 (crec
->flags
& F_HOSTS
))
315 if (cache_find_by_name(crec
, config
->hostname
, 0, cacheflags
))
317 /* use primary (first) address */
318 while (crec
&& !(crec
->flags
& F_REVERSE
))
319 crec
= cache_find_by_name(crec
, config
->hostname
, 0, cacheflags
);
321 continue; /* should be never */
322 inet_ntop(prot
, &crec
->addr
.addr
, daemon
->addrbuff
, ADDRSTRLEN
);
323 my_syslog(MS_DHCP
| LOG_WARNING
, _("%s has more than one address in hostsfile, using %s for DHCP"),
324 config
->hostname
, daemon
->addrbuff
);
327 if (prot
== AF_INET
&& !config_find_by_address(configs
, crec
->addr
.addr
.addr
.addr4
))
329 config
->addr
= crec
->addr
.addr
.addr
.addr4
;
330 config
->flags
|= CONFIG_ADDR
| CONFIG_ADDR_HOSTS
;
335 if (prot
== AF_INET6
&& !config_find_by_address6(configs
, &crec
->addr
.addr
.addr
.addr6
, 128, 0))
337 memcpy(&config
->addr6
, &crec
->addr
.addr
.addr
.addr6
, IN6ADDRSZ
);
338 config
->flags
|= CONFIG_ADDR6
| CONFIG_ADDR_HOSTS
;
343 inet_ntop(prot
, &crec
->addr
.addr
, daemon
->addrbuff
, ADDRSTRLEN
);
344 my_syslog(MS_DHCP
| LOG_WARNING
, _("duplicate IP address %s (%s) in dhcp-config directive"),
345 daemon
->addrbuff
, config
->hostname
);