Annotation of embedaddon/dnsmasq/contrib/wrt/dhcp_lease_time.c, revision 1.1.1.1
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: 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>