Annotation of embedaddon/dnsmasq/contrib/lease-tools/dhcp_lease_time.c, revision 1.1.1.3

1.1       misho       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);
1.1.1.2   misho      86:           if (end - p < (2 + opt_len))
1.1       misho      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:  
1.1.1.3 ! misho     156:   if (inet_pton(AF_INET, argv[1], &lease) < 1)
        !           157:     {
        !           158:       fprintf(stderr, "invalid address: %s\n", argv[1]);
        !           159:       exit(1);
        !           160:     }
1.1       misho     161:    
                    162:   memset(&packet, 0, sizeof(packet));
                    163:  
                    164:   packet.hlen = 0;
                    165:   packet.htype = 0;
                    166: 
                    167:   packet.op = BOOTREQUEST;
                    168:   packet.ciaddr = lease;
                    169:   packet.cookie = htonl(DHCP_COOKIE);
                    170: 
                    171:   *(p++) = OPTION_MESSAGE_TYPE;
                    172:   *(p++) = 1;
                    173:   *(p++) = DHCPINFORM;
                    174: 
1.1.1.2   misho     175:   /* Explicitly request the lease time, it won't be sent otherwise:
1.1       misho     176:      this is a dnsmasq extension, not standard. */
                    177:   *(p++) = OPTION_REQUESTED_OPTIONS;
                    178:   *(p++) = 1;
                    179:   *(p++) = OPTION_LEASE_TIME;
                    180:   
                    181:   *(p++) = OPTION_END;
                    182:  
1.1.1.3 ! misho     183:   dest.sin_family = AF_INET;
        !           184:   (void)inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr);
1.1       misho     185:   dest.sin_port = ntohs(DHCP_SERVER_PORT);
                    186:   
                    187:   if (sendto(fd, &packet, sizeof(packet), 0, 
                    188:             (struct sockaddr *)&dest, sizeof(dest)) == -1)
                    189:     {
                    190:       perror("sendto failed");
                    191:       exit(1);
                    192:     }
                    193: 
                    194:   alarm(3); /* noddy timeout. */
                    195: 
                    196:   rc = recv(fd, &packet, sizeof(packet), 0);
                    197:   
                    198:   if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
                    199:     {
                    200:       perror("recv failed");
                    201:       exit(1);
                    202:     }
                    203: 
                    204:   if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
                    205:     {
                    206:       unsigned int t = option_uint(p, 4);
                    207:       if (t == 0xffffffff)
                    208:        printf("infinite");
                    209:       else
                    210:        {
                    211:          unsigned int x;
                    212:          if ((x = t/86400))
1.1.1.2   misho     213:            printf("%ud", x);
1.1       misho     214:          if ((x = (t/3600)%24))
1.1.1.2   misho     215:            printf("%uh", x);
1.1       misho     216:          if ((x = (t/60)%60))
1.1.1.2   misho     217:            printf("%um", x);
1.1       misho     218:          if ((x = t%60))
1.1.1.2   misho     219:            printf("%us", x);
1.1       misho     220:        }
                    221:       return 0;
                    222:     }
                    223: 
                    224:   return 1; /* no lease */
                    225: }

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