~ubuntu-branches/debian/lenny/dnsmasq/lenny

« back to all changes in this revision

Viewing changes to contrib/wrt/dhcp_lease_time.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Kelley
  • Date: 2008-07-20 19:27:11 UTC
  • mfrom: (0.3.1 upstream) (9.1.4 hardy)
  • Revision ID: james.westby@ubuntu.com-20080720192711-b0lg0kl8egyg0v1b
Tags: 2.45-1
New upstream - fixes regression when min-port not set.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
   Requires dnsmasq 2.40 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_END               255
 
50
#define DHCPINFORM               8
 
51
#define DHCP_SERVER_PORT         67
 
52
 
 
53
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
 
54
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
 
55
 
 
56
 
 
57
typedef unsigned char u8;
 
58
typedef unsigned short u16;
 
59
typedef unsigned int u32;
 
60
 
 
61
struct dhcp_packet {
 
62
  u8 op, htype, hlen, hops;
 
63
  u32 xid;
 
64
  u16 secs, flags;
 
65
  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
 
66
  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
 
67
  u32 cookie;
 
68
  unsigned char options[308];
 
69
};
 
70
 
 
71
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
 
72
{
 
73
  while (*p != OPTION_END) 
 
74
    {
 
75
      if (p >= end)
 
76
        return NULL; /* malformed packet */
 
77
      else if (*p == OPTION_PAD)
 
78
        p++;
 
79
      else 
 
80
        { 
 
81
          int opt_len;
 
82
          if (p >= end - 2)
 
83
            return NULL; /* malformed packet */
 
84
          opt_len = option_len(p);
 
85
          if (p >= end - (2 + opt_len))
 
86
            return NULL; /* malformed packet */
 
87
          if (*p == opt && opt_len >= minsize)
 
88
            return p;
 
89
          p += opt_len + 2;
 
90
        }
 
91
    }
 
92
  
 
93
  return opt == OPTION_END ? p : NULL;
 
94
}
 
95
 
 
96
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
 
97
{
 
98
  unsigned char *ret, *overload;
 
99
  
 
100
  /* skip over DHCP cookie; */
 
101
  if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize)))
 
102
    return ret;
 
103
 
 
104
  /* look for overload option. */
 
105
  if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
 
106
    return NULL;
 
107
  
 
108
  /* Can we look in filename area ? */
 
109
  if ((overload[2] & 1) &&
 
110
      (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
 
111
    return ret;
 
112
 
 
113
  /* finally try sname area */
 
114
  if ((overload[2] & 2) &&
 
115
      (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
 
116
    return ret;
 
117
 
 
118
  return NULL;
 
119
}
 
120
 
 
121
static unsigned int option_uint(unsigned char *opt, int size)
 
122
{
 
123
  /* this worries about unaligned data and byte order */
 
124
  unsigned int ret = 0;
 
125
  int i;
 
126
  unsigned char *p = option_ptr(opt);
 
127
  
 
128
  for (i = 0; i < size; i++)
 
129
    ret = (ret << 8) | *p++;
 
130
 
 
131
  return ret;
 
132
}
 
133
 
 
134
int main(int argc, char **argv)
 
135
 
136
  struct in_addr lease;
 
137
  struct dhcp_packet packet;
 
138
  unsigned char *p = packet.options;
 
139
  struct sockaddr_in dest;
 
140
  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 
141
  ssize_t rc;
 
142
  
 
143
  if (argc < 2)
 
144
    { 
 
145
      fprintf(stderr, "usage: dhcp_lease_time <address>\n");
 
146
      exit(1);
 
147
    }
 
148
 
 
149
  if (fd == -1)
 
150
    {
 
151
      perror("cannot create socket");
 
152
      exit(1);
 
153
    }
 
154
 
 
155
  lease.s_addr = inet_addr(argv[1]);
 
156
   
 
157
  memset(&packet, 0, sizeof(packet));
 
158
 
 
159
  packet.hlen = 0;
 
160
  packet.htype = 0;
 
161
 
 
162
  packet.op = BOOTREQUEST;
 
163
  packet.ciaddr = lease;
 
164
  packet.cookie = htonl(DHCP_COOKIE);
 
165
 
 
166
  *(p++) = OPTION_MESSAGE_TYPE;
 
167
  *(p++) = 1;
 
168
  *(p++) = DHCPINFORM;
 
169
 
 
170
  *(p++) = OPTION_END;
 
171
 
 
172
  dest.sin_family = AF_INET; 
 
173
  dest.sin_addr.s_addr = inet_addr("127.0.0.1");
 
174
  dest.sin_port = ntohs(DHCP_SERVER_PORT);
 
175
  
 
176
  if (sendto(fd, &packet, sizeof(packet), 0, 
 
177
             (struct sockaddr *)&dest, sizeof(dest)) == -1)
 
178
    {
 
179
      perror("sendto failed");
 
180
      exit(1);
 
181
    }
 
182
 
 
183
  alarm(3); /* noddy timeout. */
 
184
 
 
185
  rc = recv(fd, &packet, sizeof(packet), 0);
 
186
  
 
187
  if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options)))
 
188
    {
 
189
      perror("recv failed");
 
190
      exit(1);
 
191
    }
 
192
 
 
193
  if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4)))
 
194
    {
 
195
      unsigned int t = option_uint(p, 4);
 
196
      if (t == 0xffffffff)
 
197
        printf("infinite");
 
198
      else
 
199
        {
 
200
          unsigned int x;
 
201
          if ((x = t/86400))
 
202
            printf("%dd", x);
 
203
          if ((x = (t/3600)%24))
 
204
            printf("%dh", x);
 
205
          if ((x = (t/60)%60))
 
206
            printf("%dm", x);
 
207
          if ((x = t%60))
 
208
            printf("%ds", x);
 
209
        }
 
210
      return 0;
 
211
    }
 
212
 
 
213
  return 1; /* no lease */
 
214
}