File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>