Annotation of embedaddon/dnsmasq/src/dhcp.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 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: #ifdef HAVE_DHCP
20:
21: struct iface_param {
22: struct dhcp_context *current;
23: int ind;
24: };
25:
26: struct match_param {
27: int ind, matched;
28: struct in_addr netmask, broadcast, addr;
29: };
30:
1.1.1.2 misho 31: static int complete_context(struct in_addr local, int if_index, char *label,
1.1 misho 32: struct in_addr netmask, struct in_addr broadcast, void *vparam);
1.1.1.2 misho 33: static int check_listen_addrs(struct in_addr local, int if_index, char *label,
1.1 misho 34: struct in_addr netmask, struct in_addr broadcast, void *vparam);
1.1.1.5 ! misho 35: static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz);
1.1.1.2 misho 36: static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
1.1 misho 37:
38: static int make_fd(int port)
39: {
40: int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
41: struct sockaddr_in saddr;
42: int oneopt = 1;
43: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
44: int mtu = IP_PMTUDISC_DONT;
45: #endif
46: #if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
47: int tos = IPTOS_CLASS_CS6;
48: #endif
49:
50: if (fd == -1)
51: die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
52:
53: if (!fix_fd(fd) ||
54: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
55: setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
56: #endif
57: #if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
58: setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
59: #endif
60: #if defined(HAVE_LINUX_NETWORK)
61: setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
62: #else
63: setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
64: #endif
65: setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
66: die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
67:
1.1.1.4 misho 68: /* When bind-interfaces is set, there might be more than one dnsmasq
1.1 misho 69: instance binding port 67. That's OK if they serve different networks.
1.1.1.4 misho 70: Need to set REUSEADDR|REUSEPORT to make this possible.
1.1 misho 71: Handle the case that REUSEPORT is defined, but the kernel doesn't
72: support it. This handles the introduction of REUSEPORT on Linux. */
73: if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
74: {
1.1.1.2 misho 75: int rc = 0;
1.1 misho 76:
77: #ifdef SO_REUSEPORT
78: if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
1.1.1.2 misho 79: errno == ENOPROTOOPT)
80: rc = 0;
1.1 misho 81: #endif
82:
1.1.1.2 misho 83: if (rc != -1)
1.1 misho 84: rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
85:
86: if (rc == -1)
87: die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
88: }
89:
90: memset(&saddr, 0, sizeof(saddr));
91: saddr.sin_family = AF_INET;
92: saddr.sin_port = htons(port);
93: saddr.sin_addr.s_addr = INADDR_ANY;
94: #ifdef HAVE_SOCKADDR_SA_LEN
95: saddr.sin_len = sizeof(struct sockaddr_in);
96: #endif
97:
98: if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
99: die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
100:
101: return fd;
102: }
103:
104: void dhcp_init(void)
105: {
106: #if defined(HAVE_BSD_NETWORK)
107: int oneopt = 1;
108: #endif
109:
110: daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
111: if (daemon->enable_pxe)
112: daemon->pxefd = make_fd(PXE_PORT);
113: else
114: daemon->pxefd = -1;
115:
116: #if defined(HAVE_BSD_NETWORK)
117: /* When we're not using capabilities, we need to do this here before
118: we drop root. Also, set buffer size small, to avoid wasting
119: kernel buffers */
120:
121: if (option_bool(OPT_NO_PING))
122: daemon->dhcp_icmp_fd = -1;
123: else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
124: setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
125: die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET);
126:
127: /* Make BPF raw send socket */
128: init_bpf();
129: #endif
130: }
131:
132: void dhcp_packet(time_t now, int pxe_fd)
133: {
134: int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
135: struct dhcp_packet *mess;
136: struct dhcp_context *context;
1.1.1.2 misho 137: struct dhcp_relay *relay;
138: int is_relay_reply = 0;
1.1 misho 139: struct iname *tmp;
140: struct ifreq ifr;
141: struct msghdr msg;
142: struct sockaddr_in dest;
143: struct cmsghdr *cmptr;
144: struct iovec iov;
145: ssize_t sz;
1.1.1.4 misho 146: int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
1.1.1.3 misho 147: int rcvd_iface_index;
1.1 misho 148: struct in_addr iface_addr;
149: struct iface_param parm;
1.1.1.4 misho 150: time_t recvtime = now;
1.1 misho 151: #ifdef HAVE_LINUX_NETWORK
152: struct arpreq arp_req;
1.1.1.4 misho 153: struct timeval tv;
1.1 misho 154: #endif
155:
156: union {
157: struct cmsghdr align; /* this ensures alignment */
158: #if defined(HAVE_LINUX_NETWORK)
159: char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
160: #elif defined(HAVE_SOLARIS_NETWORK)
161: char control[CMSG_SPACE(sizeof(unsigned int))];
162: #elif defined(HAVE_BSD_NETWORK)
163: char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
164: #endif
165: } control_u;
166: struct dhcp_bridge *bridge, *alias;
167:
168: msg.msg_controllen = sizeof(control_u);
169: msg.msg_control = control_u.control;
170: msg.msg_name = &dest;
171: msg.msg_namelen = sizeof(dest);
172: msg.msg_iov = &daemon->dhcp_packet;
173: msg.msg_iovlen = 1;
174:
175: if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
176: (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
177: return;
1.1.1.5 ! misho 178:
! 179: #ifdef HAVE_DUMPFILE
! 180: dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, fd);
! 181: #endif
! 182:
! 183: #if defined (HAVE_LINUX_NETWORK)
1.1.1.4 misho 184: if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
185: recvtime = tv.tv_sec;
1.1.1.5 ! misho 186:
1.1 misho 187: if (msg.msg_controllen >= sizeof(struct cmsghdr))
188: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
189: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
190: {
191: union {
192: unsigned char *c;
193: struct in_pktinfo *p;
194: } p;
195: p.c = CMSG_DATA(cmptr);
196: iface_index = p.p->ipi_ifindex;
197: if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
198: unicast_dest = 1;
199: }
200:
201: #elif defined(HAVE_BSD_NETWORK)
202: if (msg.msg_controllen >= sizeof(struct cmsghdr))
203: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
204: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
205: {
206: union {
207: unsigned char *c;
208: struct sockaddr_dl *s;
209: } p;
210: p.c = CMSG_DATA(cmptr);
211: iface_index = p.s->sdl_index;
212: }
213:
214: #elif defined(HAVE_SOLARIS_NETWORK)
215: if (msg.msg_controllen >= sizeof(struct cmsghdr))
216: for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
217: if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
218: {
219: union {
220: unsigned char *c;
221: unsigned int *i;
222: } p;
223: p.c = CMSG_DATA(cmptr);
224: iface_index = *(p.i);
225: }
226: #endif
227:
1.1.1.4 misho 228: if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
229: ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
1.1 misho 230: return;
1.1.1.4 misho 231:
232: mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
233: loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
234:
1.1 misho 235: #ifdef HAVE_LINUX_NETWORK
236: /* ARP fiddling uses original interface even if we pretend to use a different one. */
1.1.1.4 misho 237: safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
1.1 misho 238: #endif
239:
1.1.1.3 misho 240: /* If the interface on which the DHCP request was received is an
241: alias of some other interface (as specified by the
242: --bridge-interface option), change ifr.ifr_name so that we look
243: for DHCP contexts associated with the aliased interface instead
244: of with the aliasing one. */
245: rcvd_iface_index = iface_index;
1.1 misho 246: for (bridge = daemon->bridges; bridge; bridge = bridge->next)
247: {
248: for (alias = bridge->alias; alias; alias = alias->next)
1.1.1.3 misho 249: if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
1.1 misho 250: {
251: if (!(iface_index = if_nametoindex(bridge->iface)))
252: {
1.1.1.3 misho 253: my_syslog(MS_DHCP | LOG_WARNING,
254: _("unknown interface %s in bridge-interface"),
255: bridge->iface);
1.1 misho 256: return;
257: }
258: else
259: {
1.1.1.4 misho 260: safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
1.1 misho 261: break;
262: }
263: }
264:
265: if (alias)
266: break;
267: }
268:
269: #ifdef MSG_BCAST
270: /* OpenBSD tells us when a packet was broadcast */
271: if (!(msg.msg_flags & MSG_BCAST))
272: unicast_dest = 1;
273: #endif
274:
1.1.1.2 misho 275: if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
1.1 misho 276: {
1.1.1.2 misho 277: /* Reply from server, using us as relay. */
1.1.1.4 misho 278: rcvd_iface_index = relay->iface_index;
279: if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
1.1.1.2 misho 280: return;
281: is_relay_reply = 1;
282: iov.iov_len = sz;
283: #ifdef HAVE_LINUX_NETWORK
1.1.1.4 misho 284: safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
1.1.1.2 misho 285: #endif
1.1 misho 286: }
1.1.1.2 misho 287: else
1.1 misho 288: {
1.1.1.2 misho 289: ifr.ifr_addr.sa_family = AF_INET;
290: if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
291: iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
292: else
293: {
1.1.1.4 misho 294: if (iface_check(AF_INET, NULL, ifr.ifr_name, NULL))
295: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
1.1.1.2 misho 296: return;
297: }
298:
299: for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
300: if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
301: return;
302:
303: /* unlinked contexts/relays are marked by context->current == context */
304: for (context = daemon->dhcp; context; context = context->next)
305: context->current = context;
306:
307: parm.current = NULL;
308: parm.ind = iface_index;
1.1 misho 309:
1.1.1.4 misho 310: if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
1.1.1.2 misho 311: {
312: /* If we failed to match the primary address of the interface, see if we've got a --listen-address
313: for a secondary */
314: struct match_param match;
315:
316: match.matched = 0;
317: match.ind = iface_index;
318:
319: if (!daemon->if_addrs ||
320: !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
321: !match.matched)
322: return;
323:
324: iface_addr = match.addr;
325: /* make sure secondary address gets priority in case
326: there is more than one address on the interface in the same subnet */
327: complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
328: }
1.1.1.5 ! misho 329:
! 330: if (relay_upstream4(iface_index, mess, (size_t)sz))
! 331: return;
1.1.1.2 misho 332:
333: if (!iface_enumerate(AF_INET, &parm, complete_context))
334: return;
335:
1.1.1.5 ! misho 336: /* Check for a relay again after iface_enumerate/complete_context has had
! 337: chance to fill in relay->iface_index fields. This handles first time through
! 338: and any changes in interface config. */
! 339: if (relay_upstream4(iface_index, mess, (size_t)sz))
1.1.1.2 misho 340: return;
1.1.1.5 ! misho 341:
1.1.1.2 misho 342: /* May have configured relay, but not DHCP server */
343: if (!daemon->dhcp)
1.1 misho 344: return;
345:
1.1.1.2 misho 346: lease_prune(NULL, now); /* lose any expired leases */
347: iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
1.1.1.4 misho 348: now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
1.1.1.2 misho 349: lease_update_file(now);
350: lease_update_dns(0);
1.1 misho 351:
1.1.1.2 misho 352: if (iov.iov_len == 0)
353: return;
354: }
1.1.1.4 misho 355:
1.1 misho 356: msg.msg_name = &dest;
357: msg.msg_namelen = sizeof(dest);
358: msg.msg_control = NULL;
359: msg.msg_controllen = 0;
360: msg.msg_iov = &iov;
361: iov.iov_base = daemon->dhcp_packet.iov_base;
362:
363: /* packet buffer may have moved */
364: mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
365:
366: #ifdef HAVE_SOCKADDR_SA_LEN
367: dest.sin_len = sizeof(struct sockaddr_in);
368: #endif
369:
370: if (pxe_fd)
371: {
372: if (mess->ciaddr.s_addr != 0)
373: dest.sin_addr = mess->ciaddr;
374: }
1.1.1.2 misho 375: else if (mess->giaddr.s_addr && !is_relay_reply)
1.1 misho 376: {
377: /* Send to BOOTP relay */
378: dest.sin_port = htons(daemon->dhcp_server_port);
379: dest.sin_addr = mess->giaddr;
380: }
381: else if (mess->ciaddr.s_addr)
382: {
383: /* If the client's idea of its own address tallys with
384: the source address in the request packet, we believe the
385: source port too, and send back to that. If we're replying
386: to a DHCPINFORM, trust the source address always. */
387: if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
1.1.1.2 misho 388: dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
1.1 misho 389: {
390: dest.sin_port = htons(daemon->dhcp_client_port);
391: dest.sin_addr = mess->ciaddr;
392: }
393: }
394: #if defined(HAVE_LINUX_NETWORK)
1.1.1.3 misho 395: else
1.1 misho 396: {
1.1.1.3 misho 397: /* fill cmsg for outbound interface (both broadcast & unicast) */
1.1 misho 398: struct in_pktinfo *pkt;
399: msg.msg_control = control_u.control;
400: msg.msg_controllen = sizeof(control_u);
401: cmptr = CMSG_FIRSTHDR(&msg);
402: pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
1.1.1.3 misho 403: pkt->ipi_ifindex = rcvd_iface_index;
1.1 misho 404: pkt->ipi_spec_dst.s_addr = 0;
1.1.1.4 misho 405: msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
406: cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1.1 misho 407: cmptr->cmsg_level = IPPROTO_IP;
1.1.1.3 misho 408: cmptr->cmsg_type = IP_PKTINFO;
409:
410: if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
411: mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
412: {
413: /* broadcast to 255.255.255.255 (or mac address invalid) */
414: dest.sin_addr.s_addr = INADDR_BROADCAST;
415: dest.sin_port = htons(daemon->dhcp_client_port);
416: }
417: else
418: {
419: /* unicast to unconfigured client. Inject mac address direct into ARP cache.
420: struct sockaddr limits size to 14 bytes. */
421: dest.sin_addr = mess->yiaddr;
422: dest.sin_port = htons(daemon->dhcp_client_port);
423: memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
424: arp_req.arp_ha.sa_family = mess->htype;
425: memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
426: /* interface name already copied in */
427: arp_req.arp_flags = ATF_COM;
428: if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
429: my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
430: }
1.1 misho 431: }
432: #elif defined(HAVE_SOLARIS_NETWORK)
433: else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
434: {
435: /* broadcast to 255.255.255.255 (or mac address invalid) */
436: dest.sin_addr.s_addr = INADDR_BROADCAST;
437: dest.sin_port = htons(daemon->dhcp_client_port);
438: /* note that we don't specify the interface here: that's done by the
439: IP_BOUND_IF sockopt lower down. */
440: }
441: else
442: {
443: /* unicast to unconfigured client. Inject mac address direct into ARP cache.
444: Note that this only works for ethernet on solaris, because we use SIOCSARP
445: and not SIOCSXARP, which would be perfect, except that it returns ENXIO
446: mysteriously. Bah. Fall back to broadcast for other net types. */
447: struct arpreq req;
448: dest.sin_addr = mess->yiaddr;
449: dest.sin_port = htons(daemon->dhcp_client_port);
450: *((struct sockaddr_in *)&req.arp_pa) = dest;
451: req.arp_ha.sa_family = AF_UNSPEC;
452: memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
453: req.arp_flags = ATF_COM;
454: ioctl(daemon->dhcpfd, SIOCSARP, &req);
455: }
456: #elif defined(HAVE_BSD_NETWORK)
457: else
458: {
1.1.1.5 ! misho 459: #ifdef HAVE_DUMPFILE
! 460: if (ntohs(mess->flags) & 0x8000)
! 461: dest.sin_addr.s_addr = INADDR_BROADCAST;
! 462: else
! 463: dest.sin_addr = mess->yiaddr;
! 464: dest.sin_port = htons(daemon->dhcp_client_port);
! 465:
! 466: dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
! 467: (union mysockaddr *)&dest, fd);
! 468: #endif
! 469:
1.1 misho 470: send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
471: return;
472: }
473: #endif
474:
475: #ifdef HAVE_SOLARIS_NETWORK
476: setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
477: #endif
1.1.1.5 ! misho 478:
! 479: #ifdef HAVE_DUMPFILE
! 480: dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
! 481: (union mysockaddr *)&dest, fd);
! 482: #endif
1.1 misho 483:
1.1.1.3 misho 484: while(retry_send(sendmsg(fd, &msg, 0)));
485:
486: /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
487: if (errno != 0)
1.1.1.5 ! misho 488: {
! 489: inet_ntop(AF_INET, &dest.sin_addr, daemon->addrbuff, ADDRSTRLEN);
! 490: my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
! 491: daemon->addrbuff, strerror(errno));
! 492: }
1.1 misho 493: }
1.1.1.3 misho 494:
1.1 misho 495: /* check against secondary interface addresses */
1.1.1.2 misho 496: static int check_listen_addrs(struct in_addr local, int if_index, char *label,
1.1 misho 497: struct in_addr netmask, struct in_addr broadcast, void *vparam)
498: {
499: struct match_param *param = vparam;
500: struct iname *tmp;
501:
1.1.1.2 misho 502: (void) label;
503:
1.1 misho 504: if (if_index == param->ind)
505: {
506: for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
507: if ( tmp->addr.sa.sa_family == AF_INET &&
508: tmp->addr.in.sin_addr.s_addr == local.s_addr)
509: {
510: param->matched = 1;
511: param->addr = local;
512: param->netmask = netmask;
513: param->broadcast = broadcast;
514: break;
515: }
516: }
517:
518: return 1;
519: }
520:
521: /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
522: of each interface (and any relay address) and does the following things:
523:
524: 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
525: 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
526: 3) Fills in local (this host) and router (this host or relay) addresses.
527: 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
528:
1.1.1.4 misho 529: Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
1.1 misho 530:
1.1.1.4 misho 531: static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
1.1 misho 532: {
533: struct dhcp_context *context;
1.1.1.2 misho 534:
1.1 misho 535: for (context = daemon->dhcp; context; context = context->next)
1.1.1.4 misho 536: if (!(context->flags & CONTEXT_NETMASK) &&
537: (is_same_net(addr, context->start, netmask) ||
538: is_same_net(addr, context->end, netmask)))
1.1 misho 539: {
540: if (context->netmask.s_addr != netmask.s_addr &&
1.1.1.4 misho 541: !(is_same_net(addr, context->start, netmask) &&
542: is_same_net(addr, context->end, netmask)))
1.1 misho 543: {
1.1.1.5 ! misho 544: inet_ntop(AF_INET, &context->start, daemon->dhcp_buff, DHCP_BUFF_SZ);
! 545: inet_ntop(AF_INET, &context->end, daemon->dhcp_buff2, DHCP_BUFF_SZ);
! 546: inet_ntop(AF_INET, &netmask, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 547: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
1.1.1.5 ! misho 548: daemon->dhcp_buff, daemon->dhcp_buff2, daemon->addrbuff);
1.1 misho 549: }
1.1.1.4 misho 550: context->netmask = netmask;
1.1 misho 551: }
1.1.1.4 misho 552: }
553:
554: static int complete_context(struct in_addr local, int if_index, char *label,
555: struct in_addr netmask, struct in_addr broadcast, void *vparam)
556: {
557: struct dhcp_context *context;
558: struct dhcp_relay *relay;
559: struct iface_param *param = vparam;
560: struct shared_network *share;
561:
562: (void)label;
563:
564: for (share = daemon->shared_networks; share; share = share->next)
565: {
1.1 misho 566:
1.1.1.4 misho 567: #ifdef HAVE_DHCP6
568: if (share->shared_addr.s_addr == 0)
569: continue;
570: #endif
571:
572: if (share->if_index != 0)
573: {
574: if (share->if_index != if_index)
575: continue;
576: }
577: else
578: {
579: if (share->match_addr.s_addr != local.s_addr)
580: continue;
581: }
582:
583: for (context = daemon->dhcp; context; context = context->next)
584: {
585: if (context->netmask.s_addr != 0 &&
586: is_same_net(share->shared_addr, context->start, context->netmask) &&
587: is_same_net(share->shared_addr, context->end, context->netmask))
588: {
589: /* link it onto the current chain if we've not seen it before */
590: if (context->current == context)
591: {
592: /* For a shared network, we have no way to guess what the default route should be. */
593: context->router.s_addr = 0;
594: context->local = local; /* Use configured address for Server Identifier */
595: context->current = param->current;
596: param->current = context;
597: }
598:
599: if (!(context->flags & CONTEXT_BRDCAST))
600: context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
601: }
602: }
603: }
604:
605: guess_range_netmask(local, netmask);
606:
607: for (context = daemon->dhcp; context; context = context->next)
608: {
1.1 misho 609: if (context->netmask.s_addr != 0 &&
610: is_same_net(local, context->start, context->netmask) &&
611: is_same_net(local, context->end, context->netmask))
612: {
613: /* link it onto the current chain if we've not seen it before */
614: if (if_index == param->ind && context->current == context)
615: {
616: context->router = local;
617: context->local = local;
618: context->current = param->current;
619: param->current = context;
620: }
621:
622: if (!(context->flags & CONTEXT_BRDCAST))
623: {
624: if (is_same_net(broadcast, context->start, context->netmask))
625: context->broadcast = broadcast;
626: else
627: context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
628: }
629: }
630: }
631:
1.1.1.2 misho 632: for (relay = daemon->relay4; relay; relay = relay->next)
1.1.1.5 ! misho 633: if (relay->local.addr4.s_addr == local.s_addr)
! 634: relay->iface_index = if_index;
! 635:
1.1 misho 636: return 1;
637: }
638:
639: struct dhcp_context *address_available(struct dhcp_context *context,
640: struct in_addr taddr,
641: struct dhcp_netid *netids)
642: {
643: /* Check is an address is OK for this network, check all
644: possible ranges. Make sure that the address isn't in use
645: by the server itself. */
646:
647: unsigned int start, end, addr = ntohl(taddr.s_addr);
648: struct dhcp_context *tmp;
649:
650: for (tmp = context; tmp; tmp = tmp->current)
651: if (taddr.s_addr == context->router.s_addr)
652: return NULL;
653:
654: for (tmp = context; tmp; tmp = tmp->current)
655: {
656: start = ntohl(tmp->start.s_addr);
657: end = ntohl(tmp->end.s_addr);
658:
659: if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
660: addr >= start &&
661: addr <= end &&
662: match_netid(tmp->filter, netids, 1))
663: return tmp;
664: }
665:
666: return NULL;
667: }
668:
669: struct dhcp_context *narrow_context(struct dhcp_context *context,
670: struct in_addr taddr,
671: struct dhcp_netid *netids)
672: {
673: /* We start of with a set of possible contexts, all on the current physical interface.
674: These are chained on ->current.
1.1.1.4 misho 675: Here we have an address, and return the actual context corresponding to that
1.1 misho 676: address. Note that none may fit, if the address came a dhcp-host and is outside
677: any dhcp-range. In that case we return a static range if possible, or failing that,
678: any context on the correct subnet. (If there's more than one, this is a dodgy
679: configuration: maybe there should be a warning.) */
680:
681: struct dhcp_context *tmp;
682:
683: if (!(tmp = address_available(context, taddr, netids)))
684: {
685: for (tmp = context; tmp; tmp = tmp->current)
686: if (match_netid(tmp->filter, netids, 1) &&
687: is_same_net(taddr, tmp->start, tmp->netmask) &&
688: (tmp->flags & CONTEXT_STATIC))
689: break;
690:
691: if (!tmp)
692: for (tmp = context; tmp; tmp = tmp->current)
693: if (match_netid(tmp->filter, netids, 1) &&
694: is_same_net(taddr, tmp->start, tmp->netmask) &&
695: !(tmp->flags & CONTEXT_PROXY))
696: break;
697: }
698:
699: /* Only one context allowed now */
700: if (tmp)
701: tmp->current = NULL;
702:
703: return tmp;
704: }
705:
706: struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
707: {
708: struct dhcp_config *config;
709:
710: for (config = configs; config; config = config->next)
711: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
712: return config;
713:
714: return NULL;
715: }
716:
1.1.1.4 misho 717: /* Check if and address is in use by sending ICMP ping.
718: This wrapper handles a cache and load-limiting.
719: Return is NULL is address in use, or a pointer to a cache entry
720: recording that it isn't. */
721: struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
722: {
723: static struct ping_result dummy;
724: struct ping_result *r, *victim = NULL;
725: int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
726: ((float)PING_WAIT)));
727:
728: /* check if we failed to ping addr sometime in the last
729: PING_CACHE_TIME seconds. If so, assume the same situation still exists.
730: This avoids problems when a stupid client bangs
731: on us repeatedly. As a final check, if we did more
732: than 60% of the possible ping checks in the last
733: PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
734: for (count = 0, r = daemon->ping_results; r; r = r->next)
735: if (difftime(now, r->time) > (float)PING_CACHE_TIME)
736: victim = r; /* old record */
737: else
738: {
739: count++;
740: if (r->addr.s_addr == addr.s_addr)
741: return r;
742: }
743:
744: /* didn't find cached entry */
745: if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
746: {
747: /* overloaded, or configured not to check, loopback interface, return "not in use" */
748: dummy.hash = hash;
749: return &dummy;
750: }
751: else if (icmp_ping(addr))
752: return NULL; /* address in use. */
753: else
754: {
755: /* at this point victim may hold an expired record */
756: if (!victim)
757: {
758: if ((victim = whine_malloc(sizeof(struct ping_result))))
759: {
760: victim->next = daemon->ping_results;
761: daemon->ping_results = victim;
762: }
763: }
764:
765: /* record that this address is OK for 30s
766: without more ping checks */
767: if (victim)
768: {
769: victim->addr = addr;
770: victim->time = now;
771: victim->hash = hash;
772: }
773: return victim;
774: }
775: }
776:
1.1 misho 777: int address_allocate(struct dhcp_context *context,
778: struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
1.1.1.4 misho 779: struct dhcp_netid *netids, time_t now, int loopback)
1.1 misho 780: {
781: /* Find a free address: exclude anything in use and anything allocated to
782: a particular hwaddr/clientid/hostname in our configuration.
783: Try to return from contexts which match netids first. */
784:
785: struct in_addr start, addr;
786: struct dhcp_context *c, *d;
787: int i, pass;
788: unsigned int j;
789:
790: /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
791: dispersal even with similarly-valued "strings". */
792: for (j = 0, i = 0; i < hw_len; i++)
1.1.1.3 misho 793: j = hwaddr[i] + (j << 6) + (j << 16) - j;
1.1.1.4 misho 794:
795: /* j == 0 is marker */
796: if (j == 0)
797: j = 1;
1.1 misho 798:
799: for (pass = 0; pass <= 1; pass++)
800: for (c = context; c; c = c->current)
801: if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
802: continue;
803: else if (!match_netid(c->filter, netids, pass))
804: continue;
805: else
806: {
807: if (option_bool(OPT_CONSEC_ADDR))
808: /* seed is largest extant lease addr in this context */
809: start = lease_find_max_addr(c);
810: else
811: /* pick a seed based on hwaddr */
812: start.s_addr = htonl(ntohl(c->start.s_addr) +
813: ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
814:
815: /* iterate until we find a free address. */
816: addr = start;
817:
818: do {
819: /* eliminate addresses in use by the server. */
820: for (d = context; d; d = d->current)
821: if (addr.s_addr == d->router.s_addr)
822: break;
823:
824: /* Addresses which end in .255 and .0 are broken in Windows even when using
825: supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
826: then 192.168.0.255 is a valid IP address, but not for Windows as it's
827: in the class C range. See KB281579. We therefore don't allocate these
828: addresses to avoid hard-to-diagnose problems. Thanks Bill. */
829: if (!d &&
830: !lease_find_by_addr(addr) &&
831: !config_find_by_address(daemon->dhcp_conf, addr) &&
832: (!IN_CLASSC(ntohl(addr.s_addr)) ||
833: ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
834: {
1.1.1.4 misho 835: /* in consec-ip mode, skip addresses equal to
836: the number of addresses rejected by clients. This
837: should avoid the same client being offered the same
838: address after it has rjected it. */
839: if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
840: c->addr_epoch--;
841: else
1.1 misho 842: {
1.1.1.4 misho 843: struct ping_result *r;
844:
845: if ((r = do_icmp_ping(now, addr, j, loopback)))
846: {
847: /* consec-ip mode: we offered this address for another client
848: (different hash) recently, don't offer it to this one. */
849: if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
850: {
851: *addrp = addr;
852: return 1;
853: }
854: }
855: else
1.1 misho 856: {
857: /* address in use: perturb address selection so that we are
858: less likely to try this address again. */
859: if (!option_bool(OPT_CONSEC_ADDR))
860: c->addr_epoch++;
861: }
862: }
863: }
1.1.1.4 misho 864:
1.1 misho 865: addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
866:
867: if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
868: addr = c->start;
869:
870: } while (addr.s_addr != start.s_addr);
871: }
872:
873: return 0;
874: }
875:
876: void dhcp_read_ethers(void)
877: {
878: FILE *f = fopen(ETHERSFILE, "r");
879: unsigned int flags;
880: char *buff = daemon->namebuff;
881: char *ip, *cp;
882: struct in_addr addr;
883: unsigned char hwaddr[ETHER_ADDR_LEN];
884: struct dhcp_config **up, *tmp;
885: struct dhcp_config *config;
886: int count = 0, lineno = 0;
887:
888: addr.s_addr = 0; /* eliminate warning */
889:
890: if (!f)
891: {
892: my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
893: return;
894: }
895:
896: /* This can be called again on SIGHUP, so remove entries created last time round. */
897: for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp)
898: {
899: tmp = config->next;
900: if (config->flags & CONFIG_FROM_ETHERS)
901: {
902: *up = tmp;
903: /* cannot have a clid */
904: if (config->flags & CONFIG_NAME)
905: free(config->hostname);
906: free(config->hwaddr);
907: free(config);
908: }
909: else
910: up = &config->next;
911: }
912:
913: while (fgets(buff, MAXDNAME, f))
914: {
915: char *host = NULL;
916:
917: lineno++;
918:
1.1.1.5 ! misho 919: while (strlen(buff) > 0 && isspace((unsigned char)buff[strlen(buff)-1]))
1.1 misho 920: buff[strlen(buff)-1] = 0;
921:
922: if ((*buff == '#') || (*buff == '+') || (*buff == 0))
923: continue;
924:
1.1.1.5 ! misho 925: for (ip = buff; *ip && !isspace((unsigned char)*ip); ip++);
! 926: for(; *ip && isspace((unsigned char)*ip); ip++)
1.1 misho 927: *ip = 0;
928: if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
929: {
930: my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
931: continue;
932: }
933:
934: /* check for name or dotted-quad */
935: for (cp = ip; *cp; cp++)
936: if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
937: break;
938:
939: if (!*cp)
940: {
1.1.1.5 ! misho 941: if (inet_pton(AF_INET, ip, &addr.s_addr) < 1)
1.1 misho 942: {
943: my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
944: continue;
945: }
946:
947: flags = CONFIG_ADDR;
948:
949: for (config = daemon->dhcp_conf; config; config = config->next)
950: if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
951: break;
952: }
953: else
954: {
955: int nomem;
956: if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
957: {
958: if (!nomem)
959: my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
960: free(host);
961: continue;
962: }
963:
964: flags = CONFIG_NAME;
965:
966: for (config = daemon->dhcp_conf; config; config = config->next)
967: if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
968: break;
969: }
970:
971: if (config && (config->flags & CONFIG_FROM_ETHERS))
972: {
973: my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
974: continue;
975: }
976:
977: if (!config)
978: {
979: for (config = daemon->dhcp_conf; config; config = config->next)
980: {
981: struct hwaddr_config *conf_addr = config->hwaddr;
982: if (conf_addr &&
983: conf_addr->next == NULL &&
984: conf_addr->wildcard_mask == 0 &&
985: conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
986: (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
987: memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
988: break;
989: }
990:
991: if (!config)
992: {
993: if (!(config = whine_malloc(sizeof(struct dhcp_config))))
994: continue;
995: config->flags = CONFIG_FROM_ETHERS;
996: config->hwaddr = NULL;
997: config->domain = NULL;
998: config->netid = NULL;
999: config->next = daemon->dhcp_conf;
1000: daemon->dhcp_conf = config;
1001: }
1002:
1003: config->flags |= flags;
1004:
1005: if (flags & CONFIG_NAME)
1006: {
1007: config->hostname = host;
1008: host = NULL;
1009: }
1010:
1011: if (flags & CONFIG_ADDR)
1012: config->addr = addr;
1013: }
1014:
1015: config->flags |= CONFIG_NOCLID;
1016: if (!config->hwaddr)
1017: config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
1018: if (config->hwaddr)
1019: {
1020: memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
1021: config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
1022: config->hwaddr->hwaddr_type = ARPHRD_ETHER;
1023: config->hwaddr->wildcard_mask = 0;
1024: config->hwaddr->next = NULL;
1025: }
1026: count++;
1027:
1028: free(host);
1029:
1030: }
1031:
1032: fclose(f);
1033:
1034: my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
1035: }
1036:
1037:
1038: /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
1039: for this address. If it has a domain part, that must match the set domain and
1040: it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
1041: so check here that the domain name is legal as a hostname.
1042: NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
1043: char *host_from_dns(struct in_addr addr)
1044: {
1045: struct crec *lookup;
1046:
1047: if (daemon->port == 0)
1048: return NULL; /* DNS disabled. */
1049:
1.1.1.4 misho 1050: lookup = cache_find_by_addr(NULL, (union all_addr *)&addr, 0, F_IPV4);
1.1 misho 1051:
1052: if (lookup && (lookup->flags & F_HOSTS))
1053: {
1054: char *dot, *hostname = cache_get_name(lookup);
1055: dot = strchr(hostname, '.');
1056:
1057: if (dot && strlen(dot+1) != 0)
1058: {
1059: char *d2 = get_domain(addr);
1060: if (!d2 || !hostname_isequal(dot+1, d2))
1061: return NULL; /* wrong domain */
1062: }
1063:
1064: if (!legal_hostname(hostname))
1065: return NULL;
1066:
1.1.1.4 misho 1067: safe_strncpy(daemon->dhcp_buff, hostname, 256);
1.1 misho 1068: strip_hostname(daemon->dhcp_buff);
1069:
1070: return daemon->dhcp_buff;
1071: }
1072:
1073: return NULL;
1074: }
1075:
1.1.1.5 ! misho 1076: static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
1.1.1.2 misho 1077: {
1.1.1.5 ! misho 1078: struct in_addr giaddr = mess->giaddr;
! 1079: u8 hops = mess->hops;
! 1080: struct dhcp_relay *relay;
! 1081:
1.1.1.2 misho 1082: if (mess->op != BOOTREQUEST)
1083: return 0;
1084:
1.1.1.5 ! misho 1085: for (relay = daemon->relay4; relay; relay = relay->next)
! 1086: if (relay->iface_index != 0 && relay->iface_index == iface_index)
! 1087: break;
! 1088:
! 1089: /* No relay config. */
! 1090: if (!relay)
! 1091: return 0;
1.1.1.2 misho 1092:
1.1.1.5 ! misho 1093: for (; relay; relay = relay->next)
! 1094: if (relay->iface_index != 0 && relay->iface_index == iface_index)
! 1095: {
! 1096: union mysockaddr to;
! 1097: union all_addr from;
1.1.1.2 misho 1098:
1.1.1.5 ! misho 1099: mess->hops = hops;
! 1100: mess->giaddr = giaddr;
! 1101:
! 1102: if ((mess->hops++) > 20)
! 1103: continue;
! 1104:
! 1105: /* source address == relay address */
! 1106: from.addr4 = relay->local.addr4;
1.1 misho 1107:
1.1.1.5 ! misho 1108: /* already gatewayed ? */
! 1109: if (giaddr.s_addr)
! 1110: {
! 1111: /* if so check if by us, to stomp on loops. */
! 1112: if (giaddr.s_addr == relay->local.addr4.s_addr)
! 1113: continue;
! 1114: }
! 1115: else
! 1116: {
! 1117: /* plug in our address */
! 1118: mess->giaddr.s_addr = relay->local.addr4.s_addr;
! 1119: }
! 1120:
! 1121: to.sa.sa_family = AF_INET;
! 1122: to.in.sin_addr = relay->server.addr4;
! 1123: to.in.sin_port = htons(relay->port);
! 1124:
! 1125: /* Broadcasting to server. */
! 1126: if (relay->server.addr4.s_addr == 0)
! 1127: {
! 1128: struct ifreq ifr;
! 1129:
! 1130: if (relay->interface)
! 1131: safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
! 1132:
! 1133: if (!relay->interface || strchr(relay->interface, '*') ||
! 1134: ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
! 1135: {
! 1136: my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
! 1137: continue;
! 1138: }
! 1139:
! 1140: to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
! 1141: }
! 1142:
! 1143: #ifdef HAVE_DUMPFILE
1.1.1.2 misho 1144: {
1.1.1.5 ! misho 1145: union mysockaddr fromsock;
! 1146: fromsock.in.sin_port = htons(daemon->dhcp_server_port);
! 1147: fromsock.in.sin_addr = from.addr4;
! 1148: fromsock.sa.sa_family = AF_INET;
! 1149:
! 1150: dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
1.1.1.2 misho 1151: }
1.1.1.5 ! misho 1152: #endif
! 1153:
! 1154: send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
! 1155:
! 1156: if (option_bool(OPT_LOG_OPTS))
! 1157: {
! 1158: inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
! 1159: if (relay->server.addr4.s_addr == 0)
! 1160: snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
! 1161: else
! 1162: inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
! 1163: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
! 1164: }
! 1165: }
1.1.1.2 misho 1166:
1167: return 1;
1168: }
1169:
1170:
1171: static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
1172: {
1173: struct dhcp_relay *relay;
1174:
1175: if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
1176: return NULL;
1177:
1178: for (relay = daemon->relay4; relay; relay = relay->next)
1179: {
1.1.1.4 misho 1180: if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
1.1.1.2 misho 1181: {
1182: if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
1183: return relay->iface_index != 0 ? relay : NULL;
1184: }
1185: }
1186:
1187: return NULL;
1188: }
1189:
1190: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>