Ejemplo n.º 1
0
static ssize_t netlink_recv(void)
{
  struct msghdr msg;
  struct sockaddr_nl nladdr;
  ssize_t rc;

  while (1)
    {
      msg.msg_control = NULL;
      msg.msg_controllen = 0;
      msg.msg_name = &nladdr;
      msg.msg_namelen = sizeof(nladdr);
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      msg.msg_flags = 0;
      
      while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
      
      /* make buffer big enough */
      if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
	{
	  /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
	  if ((size_t)rc == iov.iov_len)
	    {
	      if (expand_buf(&iov, rc + 100))
		continue;
	    }
	  else
	    expand_buf(&iov, rc);
	}

      /* read it for real */
      msg.msg_flags = 0;
      while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
      
      /* Make sure this is from the kernel */
      if (rc == -1 || nladdr.nl_pid == 0)
	break;
    }
      
  /* discard stuff which is truncated at this point (expand_buf() may fail) */
  if (msg.msg_flags & MSG_TRUNC)
    {
      rc = -1;
      errno = ENOMEM;
    }
  
  return rc;
}
Ejemplo n.º 2
0
Archivo: gzip.c Proyecto: mingodad/h2o
static size_t compress_chunk(h2o_mem_pool_t *pool, z_stream *zs, const void *src, size_t len, int flush, iovec_vector_t *bufs,
                             size_t bufindex)
{
    int ret;

    zs->next_in = (void *)src;
    zs->avail_in = (unsigned)len;

    /* man says: If deflate returns with avail_out == 0, this function must be called again with the same value of the flush
     * parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out).
     */
    do {
        /* expand buffer (note: in case of Z_SYNC_FLUSH we need to supply at least 6 bytes of output buffer) */
        if (bufs->entries[bufindex].len + 32 > BUF_SIZE) {
            ++bufindex;
            if (bufindex == bufs->size)
                expand_buf(pool, bufs);
            bufs->entries[bufindex].len = 0;
        }
        zs->next_out = (void *)bufs->entries[bufindex].base + bufs->entries[bufindex].len;
        zs->avail_out = (unsigned)(BUF_SIZE - bufs->entries[bufindex].len);
        ret = deflate(zs, flush);
        assert(ret == Z_OK || ret == Z_STREAM_END);
        bufs->entries[bufindex].len = BUF_SIZE - zs->avail_out;
    } while (zs->avail_out == 0 && ret != Z_STREAM_END);

    return bufindex;
}
Ejemplo n.º 3
0
dataset* getData(uint32_t rows, uint32_t cols) {
  uint32_t len=5;           //default
  uint32_t i,j,k,val,end,word;
  char     c;
  char     *buf  =  (char*   ) malloc(len  * sizeof(char));
  dataset *outSet = (dataset*) malloc(sizeof(dataset));
  outSet->rows = rows;
  outSet->cols = cols;
  outSet->data = make2DArr(rows,cols);
  outSet->best = make2DArr(rows,cols);

  // Read in Grid Data
  for(end=i=0;    !end && i<rows; ++i) {
    for(j=0;        !end && j<cols; ++j) {
      for(k=0,word=0; !end && !word  && (c=fgetc(stdin)); ++k) {
        if(k>=len)
          expand_buf(&buf,&len);
        switch(c) {
          case EOF : end = 1;  //conditionally
                     if(k==0)  //fallthrough
                       break;
          case '\n':           //fallthrough
          case ',' :           //fallthrough
          case ' ' : buf[k] = '\0';
                     sscanf(buf,"%u",&val);
                     outSet->data[i][j] = val;
                     word=1;
                     break;
          default  : buf[k] = c; break;
        }
      }
    }
  }
  return outSet;
}
Ejemplo n.º 4
0
static size_t compress_chunk(struct st_gzip_context_t *self, const void *src, size_t len, int flush, size_t bufindex)
{
    int ret;

    self->zs.next_in = (void *)src;
    self->zs.avail_in = (unsigned)len;

    /* man says: If deflate returns with avail_out == 0, this function must be called again with the same value of the flush
     * parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out).
     */
    do {
        /* expand buffer (note: in case of Z_SYNC_FLUSH we need to supply at least 6 bytes of output buffer) */
        if (self->bufs.entries[bufindex].len + 32 > BUF_SIZE) {
            ++bufindex;
            if (bufindex == self->bufs.size)
                expand_buf(&self->bufs);
            self->bufs.entries[bufindex].len = 0;
        }
        self->zs.next_out = (void *)self->bufs.entries[bufindex].base + self->bufs.entries[bufindex].len;
        self->zs.avail_out = (unsigned)(BUF_SIZE - self->bufs.entries[bufindex].len);
        ret = deflate(&self->zs, flush);
        assert(ret == Z_OK || ret == Z_STREAM_END);
        self->bufs.entries[bufindex].len = BUF_SIZE - self->zs.avail_out;
    } while (self->zs.avail_out == 0 && ret != Z_STREAM_END);

    return bufindex;
}
Ejemplo n.º 5
0
Archivo: gzip.c Proyecto: mingodad/h2o
static void send_gzip(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, int is_final)
{
    gzip_encoder_t *self = (void *)_self;
    size_t outbufindex;

    /* initialize deflate (Z_BEST_SPEED for on-the-fly compression, memlevel set to 8 as suggested by the manual) */
    if (self->bufs.size == 0) {
        deflateInit2(&self->zstream, Z_BEST_SPEED, Z_DEFLATED, WINDOW_BITS, 8, Z_DEFAULT_STRATEGY);
        expand_buf(&req->pool, &self->bufs);
    }

    /* compress */
    outbufindex = 0;
    self->bufs.entries[0].len = 0;
    if (inbufcnt != 0) {
        size_t i;
        for (i = 0; i != inbufcnt - 1; ++i)
            if (inbufs[i].len != 0)
                outbufindex =
                    compress_chunk(&req->pool, &self->zstream, inbufs[i].base, inbufs[i].len, Z_NO_FLUSH, &self->bufs, outbufindex);
        outbufindex = compress_chunk(&req->pool, &self->zstream, inbufs[i].base, inbufs[i].len, is_final ? Z_FINISH : Z_SYNC_FLUSH,
                                     &self->bufs, outbufindex);
    } else {
        outbufindex = compress_chunk(&req->pool, &self->zstream, "", 0, Z_FINISH, &self->bufs, outbufindex);
    }

    /* destroy deflate */
    if (is_final)
        deflateEnd(&self->zstream);

    h2o_ostream_send_next(&self->super, req, self->bufs.entries, outbufindex + 1, is_final);
}
Ejemplo n.º 6
0
 inline void advance(size_t s) {
   if (out == NULL) {
     expand_buf(s);
     off += s;
   } else {
     out->seekp(s, std::ios_base::cur);
   }
 }
Ejemplo n.º 7
0
void dhcp_common_init(void)
{
    /* These each hold a DHCP option max size 255
       and get a terminating zero added */
    daemon->dhcp_buff = safe_malloc(256);
    daemon->dhcp_buff2 = safe_malloc(256);
    daemon->dhcp_buff3 = safe_malloc(256);

    /* dhcp_packet is used by v4 and v6, outpacket only by v6
       sizeof(struct dhcp_packet) is as good an initial size as any,
       even for v6 */
    expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
#ifdef HAVE_DHCP6
    if (daemon->dhcp6)
        expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
#endif
}
Ejemplo n.º 8
0
 /** Directly writes "s" bytes from the memory location
  * pointed to by "c" into the stream.
  */
 inline void write(const char* c, std::streamsize s) {
   if (out == NULL) {
     expand_buf(s);
     memcpy(buf + off, c, s);
     off += s;
   } else {
     out->write(c, s);
   }
 }
Ejemplo n.º 9
0
 inline void direct_assign(const T& t) {
   if (out == NULL) {
     expand_buf(sizeof(T));
     (*reinterpret_cast<T*>(buf + off)) = t;
     off += sizeof(T);
   }
   else {
     out->write(reinterpret_cast<const char*>(&t), sizeof(T));
   }
 }
static void *fdt_wrapper_create_node(const void *devp, const char *name)
{
	int offset;

	offset = fdt_add_subnode(fdt, devp_offset(devp), name);
	if (offset == -FDT_ERR_NOSPACE) {
		expand_buf(strlen(name) + 16);
		offset = fdt_add_subnode(fdt, devp_offset(devp), name);
	}

	return offset_devp(offset);
}
static int fdt_wrapper_setprop(const void *devp, const char *name,
			       const void *buf, const int len)
{
	int rc;

	rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
	if (rc == -FDT_ERR_NOSPACE) {
		expand_buf(len + 16);
		rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
	}

	return check_err(rc);
}
Ejemplo n.º 12
0
static ssize_t netlink_recv(struct daemon *daemon)
{
  struct msghdr msg;
  ssize_t rc;

  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
    
  while (1)
    {
      msg.msg_flags = 0;
      while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
      
      /* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a 
	 big buffer and pray in that case. */
      if (rc == -1 && errno == EOPNOTSUPP)
	{
	  if (!expand_buf(&iov, 2000))
	    return -1;
	  break;
	}
      
      if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
        break;
            
      if (!expand_buf(&iov, iov.iov_len + 100))
	return -1;
    }

  /* finally, read it for real */
  while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
  
  return rc;
}
Ejemplo n.º 13
0
h2o_compress_context_t *h2o_compress_gzip_open(h2o_mem_pool_t *pool, int quality)
{
    struct st_gzip_context_t *self = h2o_mem_alloc_shared(pool, sizeof(*self), do_free);

    self->super.name = h2o_iovec_init(H2O_STRLIT("gzip"));
    self->super.compress = do_compress;
    self->zs.zalloc = alloc_cb;
    self->zs.zfree = free_cb;
    self->zs.opaque = NULL;
    /* Z_BEST_SPEED for on-the-fly compression, memlevel set to 8 as suggested by the manual */
    deflateInit2(&self->zs, quality, Z_DEFLATED, WINDOW_BITS, 8, Z_DEFAULT_STRATEGY);
    self->zs_is_open = 1;
    self->bufs = (iovec_vector_t){};
    expand_buf(&self->bufs);

    return &self->super;
}
Ejemplo n.º 14
0
int main(int argc, char* argv[]) {
  uint32_t size = 10,len = 5; /* default */
  uint32_t i,j,val,end,count,height;
  uint32_t *list = (uint32_t*) malloc(size * sizeof(uint32_t));
  char     *buf  = (char*    ) malloc(len  * sizeof(char));
  char     c;

  if(argc > 1 &&!strcmp(argv[1],"--help")) { return print_help(argv[0]); }

  /* Read in Triangle Data */
  for(count=height=end=i=0; !end && (c=fgetc(stdin)); ) {
    if(i>=len)
      expand_buf(&buf,&len);
    switch(c) {
      case EOF : end = 1;  /* conditionally */
                 if(i==0)  /* fallthrough  */
                   break;
      case '\n': ++height; /* fallthrough */
      case ' ' : if(count>=size)
                   expand_arr(&list,&size);
                 buf[i] = '\0';
                 sscanf(buf,"%u",&val);
                 list[count++] = val;
                 i=0;
                 break;
      default  : buf[i++] = c; break;
    }
  }
  /* Process Triangle Data */
  /* both loops break after control variable decrements from zero to UINT32_MAX */
  for(i=height-2; i<height; --i)
    for(j=i; j<=i; --j)
      list[getOffset(i,j)] += (list[getOffset(i+1,j)] > list[getOffset(i+1,j+1)]) ? list[getOffset(i+1,j)] : list[getOffset(i+1,j+1)];

  printf("%u\n",list[0]);
  return 0;
}
Ejemplo n.º 15
0
void dhcp_packet(time_t now)
{
  struct dhcp_packet *mess;
  struct dhcp_context *context;
  struct iname *tmp;
  struct ifreq ifr;
  struct msghdr msg;
  struct sockaddr_in dest;
  struct cmsghdr *cmptr;
  struct iovec iov;
  ssize_t sz; 
  int iface_index = 0, unicast_dest = 0, is_inform = 0;
  struct in_addr iface_addr, *addrp = NULL;
  struct iface_param parm;

  union {
    struct cmsghdr align; 
#if defined(HAVE_LINUX_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK)
    char control[CMSG_SPACE(sizeof(unsigned int))];
#elif defined(HAVE_BSD_NETWORK) 
    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
  } control_u;
  
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = &daemon->dhcp_packet;
  msg.msg_iovlen = 1;
  
  while (1)
    {
      msg.msg_flags = 0;
      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
      
      if (sz == -1)
	return;
      
      if (!(msg.msg_flags & MSG_TRUNC))
	break;

      if ((size_t)sz == daemon->dhcp_packet.iov_len)
	{
	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
	    return;
	}
      else
	{
	  expand_buf(&daemon->dhcp_packet, sz);
	  break;
	}
    }
  
  
  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
  msg.msg_controllen = sizeof(control_u);
  msg.msg_control = control_u.control;
  msg.msg_flags = 0;
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);

  while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
 
  if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
    return;
  
#if defined (HAVE_LINUX_NETWORK)
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
	{
	  iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
	    unicast_dest = 1;
	}

#elif defined(HAVE_BSD_NETWORK) 
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
        iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;

  
#elif defined(HAVE_SOLARIS_NETWORK) 
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
	iface_index = *((unsigned int *)CMSG_DATA(cmptr));
	  
#endif
	
  if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
    return;

#ifdef MSG_BCAST
  
  if (!(msg.msg_flags & MSG_BCAST))
    unicast_dest = 1;
#endif

  ifr.ifr_addr.sa_family = AF_INET;
  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
    {
      addrp = &iface_addr;
      iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }

  if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
    return;
  
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
    if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
      return;
  
  
  if (!addrp)
    {
      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
	{
	  my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
	  return;
	}
      else
	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }
  
  
  for (context = daemon->dhcp; context; context = context->next)
    context->current = context;
  
  parm.relay = mess->giaddr;
  parm.primary = iface_addr;
  parm.current = NULL;
  parm.ind = iface_index;

  if (!iface_enumerate(&parm, complete_context, NULL))
    return;
  lease_prune(NULL, now); 
  iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
			   now, unicast_dest, &is_inform);
  lease_update_file(now);
  lease_update_dns();
    
  if (iov.iov_len == 0)
    return;
  
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_iov = &iov;
  iov.iov_base = daemon->dhcp_packet.iov_base;
  
  
  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
  
#ifdef HAVE_SOCKADDR_SA_LEN
  dest.sin_len = sizeof(struct sockaddr_in);
#endif
     
  if (mess->giaddr.s_addr)
    {
      
      dest.sin_port = htons(daemon->dhcp_server_port);
      dest.sin_addr = mess->giaddr; 
    }
  else if (mess->ciaddr.s_addr)
    {
      if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
	{
	  dest.sin_port = htons(daemon->dhcp_client_port); 
	  dest.sin_addr = mess->ciaddr;
	}
    } 
#if defined(HAVE_LINUX_NETWORK)
  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
    {
      
      struct in_pktinfo *pkt;
      msg.msg_control = control_u.control;
      msg.msg_controllen = sizeof(control_u);
      cmptr = CMSG_FIRSTHDR(&msg);
      pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
      pkt->ipi_ifindex = iface_index;
      pkt->ipi_spec_dst.s_addr = 0;
      msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
      cmptr->cmsg_level = SOL_IP;
      cmptr->cmsg_type = IP_PKTINFO;  
      dest.sin_addr.s_addr = INADDR_BROADCAST;
      dest.sin_port = htons(daemon->dhcp_client_port);
    }
  else
    {
      struct arpreq req;
      dest.sin_addr = mess->yiaddr;
      dest.sin_port = htons(daemon->dhcp_client_port);
      *((struct sockaddr_in *)&req.arp_pa) = dest;
      req.arp_ha.sa_family = mess->htype;
      memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
      strncpy(req.arp_dev, ifr.ifr_name, 16);
      req.arp_flags = ATF_COM;
      ioctl(daemon->dhcpfd, SIOCSARP, &req);
    }
#elif defined(HAVE_SOLARIS_NETWORK)
  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
Ejemplo n.º 16
0
static int join_multicast_worker(struct in6_addr *local, int prefix,
                                 int scope, int if_index, int dad, void *vparam)
{
    char ifrn_name[IFNAMSIZ];
    struct ipv6_mreq mreq;
    int fd, i, max = *((int *)vparam);
    struct iname *tmp;

    (void)prefix;
    (void)scope;
    (void)dad;

    /* record which interfaces we join on, so that we do it at most one per
       interface, even when they have multiple addresses. Use outpacket
       as an array of int, since it's always allocated here and easy
       to expand for theoretical vast numbers of interfaces. */
    for (i = 0; i < max; i++)
        if (if_index == ((int *)daemon->outpacket.iov_base)[i])
            return 1;

    if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
        return 0;

    if (!indextoname(fd, if_index, ifrn_name))
    {
        close(fd);
        return 0;
    }

    close(fd);

    /* Are we doing DHCP on this interface? */
    if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
        return 1;

    for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
        if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
            return 1;

    mreq.ipv6mr_interface = if_index;

    inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);

    if (daemon->dhcp6 &&
            setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        return 0;

    inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);

    if (daemon->dhcp6 &&
            setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        return 0;

    inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);

    if (daemon->ra_contexts &&
            setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
        return 0;

    expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
    ((int *)daemon->outpacket.iov_base)[max++] = if_index;

    *((int *)vparam) = max;

    return 1;
}
Ejemplo n.º 17
0
Archivo: dhcp.c Proyecto: vlrk/dnsmasq
void dhcp_packet(time_t now, int pxe_fd)
{
  int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
  struct dhcp_packet *mess;
  struct dhcp_context *context;
  struct iname *tmp;
  struct ifreq ifr;
  struct msghdr msg;
  struct sockaddr_in dest;
  struct cmsghdr *cmptr;
  struct iovec iov;
  ssize_t sz; 
  int iface_index = 0, unicast_dest = 0, is_inform = 0;
  struct in_addr iface_addr, *addrp = NULL;
  struct iface_param parm;
#ifdef HAVE_LINUX_NETWORK
  struct arpreq arp_req;
#endif
  
  union {
    struct cmsghdr align; /* this ensures alignment */
#if defined(HAVE_LINUX_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK)
    char control[CMSG_SPACE(sizeof(unsigned int))];
#elif defined(HAVE_BSD_NETWORK) 
    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
  } control_u;
 
  /* NETGEAR Changes Start  */
  #ifdef INCLUDE_ATT_GUI        
  {
    extern  void  netmgr_sig_request(int req);
        /*reset network manager signal request flag*/
    netmgr_sig_request(0);
  }
  #endif
  /* NETGEAR Changes End */

 
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = &daemon->dhcp_packet;
  msg.msg_iovlen = 1;
  
  while (1)
    {
      msg.msg_flags = 0;
      while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
      
      if (sz == -1)
	return;
      
      if (!(msg.msg_flags & MSG_TRUNC))
	break;

      /* Very new Linux kernels return the actual size needed, 
	 older ones always return truncated size */
      if ((size_t)sz == daemon->dhcp_packet.iov_len)
	{
	  if (!expand_buf(&daemon->dhcp_packet, sz + 100))
	    return;
	}
      else
	{
	  expand_buf(&daemon->dhcp_packet, sz);
	  break;
	}
    }
  
  /* expand_buf may have moved buffer */
  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
  msg.msg_controllen = sizeof(control_u);
  msg.msg_control = control_u.control;
  msg.msg_flags = 0;
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);

  while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
 
  if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
    return;
  
#if defined (HAVE_LINUX_NETWORK)
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
	{
	  union {
	    unsigned char *c;
	    struct in_pktinfo *p;
	  } p;
	  p.c = CMSG_DATA(cmptr);
	  iface_index = p.p->ipi_ifindex;
	  if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
	    unicast_dest = 1;
	}

#elif defined(HAVE_BSD_NETWORK) 
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
        {
	  union {
            unsigned char *c;
            struct sockaddr_dl *s;
          } p;
	  p.c = CMSG_DATA(cmptr);
	  iface_index = p.s->sdl_index;
	}
  
#elif defined(HAVE_SOLARIS_NETWORK) 
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
	{
	  union {
	    unsigned char *c;
	    unsigned int *i;
	  } p;
	  p.c = CMSG_DATA(cmptr);
	  iface_index = *(p.i);
	}
#endif
	
  if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
    return;

#ifdef HAVE_LINUX_NETWORK
  /* ARP fiddling uses original interface even if we pretend to use a different one. */
  strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
#endif 

#ifdef MSG_BCAST
  /* OpenBSD tells us when a packet was broadcast */
  if (!(msg.msg_flags & MSG_BCAST))
    unicast_dest = 1;
#endif

  ifr.ifr_addr.sa_family = AF_INET;
  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
    {
      addrp = &iface_addr;
      iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }

  if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
    return;
  
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
    if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
      return;

  /* weird libvirt-inspired access control */
  for (context = daemon->dhcp; context; context = context->next)
    if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
      break;

  if (!context)
    return;
  
  /* unlinked contexts are marked by context->current == context */
  for (context = daemon->dhcp; context; context = context->next)
    context->current = context;
  
  parm.relay = mess->giaddr;
  parm.primary = iface_addr;
  parm.current = NULL;
  parm.ind = iface_index;

    /* interface may have been changed by alias in iface_check, make sure it gets priority in case
       there is more than one address on the interface in the same subnet */
  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
    {
      my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
      return;
    }
  else
    {
      iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
      if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
	{
	  struct in_addr netmask =  ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
	  if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
	    {
	      struct in_addr broadcast =  ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
	      complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
	    }
	}
    } 

  if (!iface_enumerate(AF_INET, &parm, complete_context))
    return;
  lease_prune(NULL, now); /* lose any expired leases */
  iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 
			   now, unicast_dest, &is_inform, pxe_fd);
  lease_update_file(now);
  lease_update_dns();
    
  if (iov.iov_len == 0)
    return;
  
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_iov = &iov;
  iov.iov_base = daemon->dhcp_packet.iov_base;
  
  /* packet buffer may have moved */
  mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
  
#ifdef HAVE_SOCKADDR_SA_LEN
  dest.sin_len = sizeof(struct sockaddr_in);
#endif
  
  /* NETGEAR Changes Start  */
  #ifdef INCLUDE_ATT_GUI
  {

    extern  void  netmgr_sig_request(int req);
    /*request to send a SIGUSR2 signal to network manager after the lease is sent to the host*/
    netmgr_sig_request(1);
  }
  #endif
  /* NETGEAR Changes End */

   
  if (pxe_fd)
    { 
      if (mess->ciaddr.s_addr != 0)
	dest.sin_addr = mess->ciaddr;
    }
  else if (mess->giaddr.s_addr)
    {
      /* Send to BOOTP relay  */
      dest.sin_port = htons(daemon->dhcp_server_port);
      dest.sin_addr = mess->giaddr; 
    }
  else if (mess->ciaddr.s_addr)
    {
      /* If the client's idea of its own address tallys with
	 the source address in the request packet, we believe the
	 source port too, and send back to that.  If we're replying 
	 to a DHCPINFORM, trust the source address always. */
      if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
	{
	  dest.sin_port = htons(daemon->dhcp_client_port); 
	  dest.sin_addr = mess->ciaddr;
	}
    } 
#if defined(HAVE_LINUX_NETWORK)
  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
    {
      /* broadcast to 255.255.255.255 (or mac address invalid) */
      struct in_pktinfo *pkt;
      msg.msg_control = control_u.control;
      msg.msg_controllen = sizeof(control_u);
      cmptr = CMSG_FIRSTHDR(&msg);
      pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
      pkt->ipi_ifindex = iface_index;
      pkt->ipi_spec_dst.s_addr = 0;
      msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
      cmptr->cmsg_level = SOL_IP;
      cmptr->cmsg_type = IP_PKTINFO;  
      dest.sin_addr.s_addr = INADDR_BROADCAST;
      dest.sin_port = htons(daemon->dhcp_client_port);
    }
  else
    {
      /* unicast to unconfigured client. Inject mac address direct into ARP cache. 
	 struct sockaddr limits size to 14 bytes. */
      dest.sin_addr = mess->yiaddr;
      dest.sin_port = htons(daemon->dhcp_client_port);
      memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
      arp_req.arp_ha.sa_family = mess->htype;
      memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
      /* interface name already copied in */
      arp_req.arp_flags = ATF_COM;
      ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
    }
#elif defined(HAVE_SOLARIS_NETWORK)
  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
Ejemplo n.º 18
0
void dhcp_packet(time_t now)
{
  struct dhcp_packet *mess;
  struct dhcp_context *context;
  struct iname *tmp;
  struct ifreq ifr;
  struct msghdr msg;
  struct sockaddr_in dest;
  struct cmsghdr *cmptr;
  struct iovec iov;
  ssize_t sz; 
  int iface_index = 0, unicast_dest = 0, is_inform = 0;
  struct in_addr iface_addr, *addrp = NULL;
  struct iface_param parm;

  union {
    struct cmsghdr align; /* this ensures alignment */
#ifdef HAVE_LINUX_NETWORK
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#else
    char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
  } control_u;
  
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = &daemon->dhcp_packet;
  msg.msg_iovlen = 1;
  
  do
    {
      msg.msg_flags = 0;
      while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
    }
  while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
	 expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
  
  /* expand_buf may have moved buffer */
  mess = daemon->dhcp_packet.iov_base;
  msg.msg_controllen = sizeof(control_u);
  msg.msg_control = control_u.control;
  msg.msg_flags = 0;
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);

  while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
 
  if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
    return;
  
#if defined (HAVE_LINUX_NETWORK)
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
	{
	  iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
	  if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
	    unicast_dest = 1;
	}
  
  if (!(ifr.ifr_ifindex = iface_index) || 
      ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
    return;
  
#elif defined(IP_RECVIF)
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
	iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
  
  if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
    return;
  
#ifdef MSG_BCAST
  /* OpenBSD tells us when a packet was broadcast */
  if (!(msg.msg_flags & MSG_BCAST))
    unicast_dest = 1;
#endif

#else
  /* fallback for systems without IP_RECVIF - allow only one interface
     and assume packets arrive from it - yuk. */
  {
    struct iname *name;
    for (name = daemon->if_names; name->isloop; name = name->next);
    strcpy(ifr.ifr_name, name->name);
    iface_index = if_nametoindex(name->name);
  }
#endif

  ifr.ifr_addr.sa_family = AF_INET;
  if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
    {
      addrp = &iface_addr;
      iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }

  if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
    return;
  
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
    if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
      return;
  
  /* interface may have been changed by alias in iface_check */
  if (!addrp)
    {
      if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1)
	{
	  my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
	  return;
	}
      else
	iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }
  
  /* unlinked contexts are marked by context->current == context */
  for (context = daemon->dhcp; context; context = context->next)
    context->current = context;
  
  parm.relay = mess->giaddr;
  parm.primary = iface_addr;
  parm.current = NULL;
  parm.ind = iface_index;

  if (!iface_enumerate(&parm, complete_context, NULL))
    return;
  lease_prune(NULL, now); /* lose any expired leases */
  iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, (size_t)sz, 
			   now, unicast_dest, &is_inform);
  lease_update_file(now);
  lease_update_dns();
    
  if (iov.iov_len == 0)
    return;
  
  msg.msg_name = &dest;
  msg.msg_namelen = sizeof(dest);
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_iov = &iov;
  iov.iov_base = daemon->dhcp_packet.iov_base;
  
  /* packet buffer may have moved */
  mess = daemon->dhcp_packet.iov_base;
  
#ifdef HAVE_SOCKADDR_SA_LEN
  dest.sin_len = sizeof(struct sockaddr_in);
#endif
     
  if (mess->giaddr.s_addr)
    {
      /* Send to BOOTP relay  */
      dest.sin_port = htons(DHCP_SERVER_PORT);
      dest.sin_addr = mess->giaddr; 
    }
  else if (mess->ciaddr.s_addr)
    {
      /* If the client's idea of its own address tallys with
	 the source address in the request packet, we believe the
	 source port too, and send back to that.  If we're replying 
	 to a DHCPINFORM, trust the source address always. */
      if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
	  dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
	{
	  dest.sin_port = htons(DHCP_CLIENT_PORT); 
	  dest.sin_addr = mess->ciaddr;
	}
    } 
#ifdef HAVE_LINUX_NETWORK
  else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
	   mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
    {
      /* broadcast to 255.255.255.255 (or mac address invalid) */
      struct in_pktinfo *pkt;
      msg.msg_control = control_u.control;
      msg.msg_controllen = sizeof(control_u);
      cmptr = CMSG_FIRSTHDR(&msg);
      dest.sin_addr.s_addr = INADDR_BROADCAST;
      dest.sin_port = htons(DHCP_CLIENT_PORT);
      pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
      pkt->ipi_ifindex = iface_index;
      pkt->ipi_spec_dst.s_addr = 0;
      msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
      cmptr->cmsg_level = SOL_IP;
      cmptr->cmsg_type = IP_PKTINFO;
    }
  else
    {
      /* unicast to unconfigured client. Inject mac address direct into ARP cache. 
	 struct sockaddr limits size to 14 bytes. */
      struct arpreq req;
      dest.sin_addr = mess->yiaddr;
      dest.sin_port = htons(DHCP_CLIENT_PORT);
      *((struct sockaddr_in *)&req.arp_pa) = dest;
      req.arp_ha.sa_family = mess->htype;
      memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
      strncpy(req.arp_dev, ifr.ifr_name, 16);
      req.arp_flags = ATF_COM;
      ioctl(daemon->dhcpfd, SIOCSARP, &req);
    }
#else
  else 
    {