File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / contrib / wrt / dhcp_lease_time.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years, 1 month ago) by misho
Branches: elwix, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

    1: /* Copyright (c) 2007 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.
    6: 
    7:    This program is distributed in the hope that it will be useful,
    8:    but WITHOUT ANY WARRANTY; without even the implied warranty of
    9:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10:    GNU General Public License for more details.
   11: */
   12: 
   13: /* dhcp_lease_time <address> */
   14: 
   15: /* Send a DHCPINFORM message to a dnsmasq server running on the local host
   16:    and print (to stdout) the time remaining in any lease for the given
   17:    address. The time is given as string printed to stdout.
   18: 
   19:    If an error occurs or no lease exists for the given address, 
   20:    nothing is sent to stdout a message is sent to stderr and a
   21:    non-zero error code is returned.
   22: 
   23:    This version requires dnsmasq 2.67 or later. 
   24: */
   25: 
   26: #include <sys/types.h> 
   27: #include <netinet/in.h>
   28: #include <net/if.h>
   29: #include <arpa/inet.h>
   30: #include <sys/socket.h>
   31: #include <unistd.h>
   32: #include <stdio.h>
   33: #include <string.h>
   34: #include <stdlib.h>
   35: #include <net/if_arp.h>
   36: #include <sys/ioctl.h>
   37: #include <linux/types.h>
   38: #include <linux/netlink.h>
   39: #include <linux/rtnetlink.h>
   40: #include <errno.h>
   41: 
   42: #define DHCP_CHADDR_MAX          16
   43: #define BOOTREQUEST              1
   44: #define DHCP_COOKIE              0x63825363
   45: #define OPTION_PAD               0
   46: #define OPTION_LEASE_TIME        51
   47: #define OPTION_OVERLOAD          52
   48: #define OPTION_MESSAGE_TYPE      53
   49: #define OPTION_REQUESTED_OPTIONS 55
   50: #define OPTION_END               255
   51: #define DHCPINFORM               8
   52: #define DHCP_SERVER_PORT         67
   53: 
   54: #define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
   55: #define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
   56: 
   57: 
   58: typedef unsigned char u8;
   59: typedef unsigned short u16;
   60: typedef unsigned int u32;
   61: 
   62: struct dhcp_packet {
   63:   u8 op, htype, hlen, hops;
   64:   u32 xid;
   65:   u16 secs, flags;
   66:   struct in_addr ciaddr, yiaddr, siaddr, giaddr;
   67:   u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
   68:   u32 cookie;
   69:   unsigned char options[308];
   70: };
   71: 
   72: static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
   73: {
   74:   while (*p != OPTION_END) 
   75:     {
   76:       if (p >= end)
   77:         return NULL; /* malformed packet */
   78:       else if (*p == OPTION_PAD)
   79:         p++;
   80:       else 
   81:         { 
   82:           int opt_len;
   83:           if (p >= end - 2)
   84:             return NULL; /* malformed packet */
   85:           opt_len = option_len(p);
   86:           if (p >= end - (2 + opt_len))
   87:             return NULL; /* malformed packet */
   88:           if (*p == opt && opt_len >= minsize)
   89:             return p;
   90:           p += opt_len + 2;
   91:         }
   92:     }
   93:   
   94:   return opt == OPTION_END ? p : NULL;
   95: }
   96:  
   97: static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
   98: {
   99:   unsigned char *ret, *overload;
  100:   
  101:   /* skip over DHCP cookie; */
  102:   if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize)))
  103:     return ret;
  104: 
  105:   /* look for overload option. */
  106:   if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
  107:     return NULL;
  108:   
  109:   /* Can we look in filename area ? */
  110:   if ((overload[2] & 1) &&
  111:       (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
  112:     return ret;
  113: 
  114:   /* finally try sname area */
  115:   if ((overload[2] & 2) &&
  116:       (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
  117:     return ret;
  118: 
  119:   return NULL;
  120: }
  121: 
  122: static unsigned int option_uint(unsigned char *opt, int size)
  123: {
  124:   /* this worries about unaligned data and byte order */
  125:   unsigned int ret = 0;
  126:   int i;
  127:   unsigned char *p = option_ptr(opt);
  128:   
  129:   for (i = 0; i < size; i++)
  130:     ret = (ret << 8) | *p++;
  131: 
  132:   return ret;
  133: }
  134: 
  135: int main(int argc, char **argv)
  136: { 
  137:   struct in_addr lease;
  138:   struct dhcp_packet packet;
  139:   unsigned char *p = packet.options;
  140:   struct sockaddr_in dest;
  141:   int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  142:   ssize_t rc;
  143:   
  144:   if (argc < 2)
  145:     { 
  146:       fprintf(stderr, "usage: dhcp_lease_time <address>\n");
  147:       exit(1);
  148:     }
  149: 
  150:   if (fd == -1)
  151:     {
  152:       perror("cannot create socket");
  153:       exit(1);
  154:     }
  155:  
  156:   lease.s_addr = inet_addr(argv[1]);
  157:    
  158:   memset(&packet, 0, sizeof(packet));
  159:  
  160:   packet.hlen = 0;
  161:   packet.htype = 0;
  162: 
  163:   packet.op = BOOTREQUEST;
  164:   packet.ciaddr = lease;
  165:   packet.cookie = htonl(DHCP_COOKIE);
  166: 
  167:   *(p++) = OPTION_MESSAGE_TYPE;
  168:   *(p++) = 1;
  169:   *(p++) = DHCPINFORM;
  170: 
  171:   /* Explicity request the lease time, it won't be sent otherwise:
  172:      this is a dnsmasq extension, not standard. */
  173:   *(p++) = OPTION_REQUESTED_OPTIONS;
  174:   *(p++) = 1;
  175:   *(p++) = OPTION_LEASE_TIME;
  176:   
  177:   *(p++) = OPTION_END;
  178:  
  179:   dest.sin_family = AF_INET; 
  180:   dest.sin_addr.s_addr = inet_addr("127.0.0.1");
  181:   dest.sin_port = ntohs(DHCP_SERVER_PORT);
  182:   
  183:   if (sendto(fd, &packet, sizeof(packet), 0, 
  184: 	     (struct sockaddr *)&dest, sizeof(dest)) == -1)
  185:     {
  186:       perror("sendto failed");
  187:       exit(1);
  188:     }
  189: 
  190:   alarm(3); /* noddy timeout. */
  191: 
  192:   rc = recv(fd, &packet, sizeof(packet), 0);
  193:   
  194:   if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
  195:     {
  196:       perror("recv failed");
  197:       exit(1);
  198:     }
  199: 
  200:   if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
  201:     {
  202:       unsigned int t = option_uint(p, 4);
  203:       if (t == 0xffffffff)
  204: 	printf("infinite");
  205:       else
  206: 	{
  207: 	  unsigned int x;
  208: 	  if ((x = t/86400))
  209: 	    printf("%dd", x);
  210: 	  if ((x = (t/3600)%24))
  211: 	    printf("%dh", x);
  212: 	  if ((x = (t/60)%60))
  213: 	    printf("%dm", x);
  214: 	  if ((x = t%60))
  215: 	    printf("%ds", x);
  216: 	}
  217:       return 0;
  218:     }
  219: 
  220:   return 1; /* no lease */
  221: }

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