2 * dhclient.c General radius packet debug tool.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
21 * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
22 * Copyright 2010 Alan DeKok <aland@ox.org>
25 #include <freeradius-devel/ident.h>
28 #include <freeradius-devel/libradius.h>
29 #include <freeradius-devel/conf.h>
30 #include <freeradius-devel/radpaths.h>
31 #include <freeradius-devel/dhcp.h>
43 static int success = 0;
44 static int retries = 3;
45 static float timeout = 5;
47 static int server_port = 0;
48 static int packet_code = 0;
49 static fr_ipaddr_t server_ipaddr;
50 static int resend_count = 1;
52 static fr_ipaddr_t client_ipaddr;
53 static int client_port = 0;
57 static int sleep_time = -1;
59 static RADIUS_PACKET *request = NULL;
60 static RADIUS_PACKET *reply = NULL;
62 #define DHCP_CHADDR_LEN (16)
63 #define DHCP_SNAME_LEN (64)
64 #define DHCP_FILE_LEN (128)
65 #define DHCP_VEND_LEN (308)
66 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
68 static void NEVER_RETURNS usage(void)
70 fprintf(stderr, "Usage: dhclient [options] server[:port] <command>\n");
72 fprintf(stderr, " <command> One of discover, request\n");
73 fprintf(stderr, " -c count Send each packet 'count' times.\n");
74 fprintf(stderr, " -d raddb Set dictionary directory.\n");
75 fprintf(stderr, " -f file Read packets from file, not stdin.\n");
76 fprintf(stderr, " -r retries If timeout, retry sending the packet 'retries' times.\n");
77 fprintf(stderr, " -v Show program version information.\n");
78 fprintf(stderr, " -x Debugging mode.\n");
85 * Initialize the request.
87 static int request_init(const char *filename)
94 * Determine where to read the VP's from.
97 fp = fopen(filename, "r");
99 fprintf(stderr, "dhclient: Error opening %s: %s\n",
100 filename, strerror(errno));
107 request = rad_alloc(0);
112 request->vps = readvp2(fp, &filedone, "dhclient:");
115 if (fp != stdin) fclose(fp);
120 * Fix / set various options
122 for (vp = request->vps; vp != NULL; vp = vp->next) {
123 switch (vp->attribute) {
128 * Allow it to set the packet type in
129 * the attributes read from the file.
132 request->code = vp->vp_integer;
135 case PW_PACKET_DST_PORT:
136 request->dst_port = (vp->vp_integer & 0xffff);
139 case PW_PACKET_DST_IP_ADDRESS:
140 request->dst_ipaddr.af = AF_INET;
141 request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
144 case PW_PACKET_DST_IPV6_ADDRESS:
145 request->dst_ipaddr.af = AF_INET6;
146 request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
149 case PW_PACKET_SRC_PORT:
150 request->src_port = (vp->vp_integer & 0xffff);
153 case PW_PACKET_SRC_IP_ADDRESS:
154 request->src_ipaddr.af = AF_INET;
155 request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
158 case PW_PACKET_SRC_IPV6_ADDRESS:
159 request->src_ipaddr.af = AF_INET6;
160 request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
162 } /* switch over the attribute */
164 } /* loop over the VP's we read in */
166 if (fp != stdin) fclose(fp);
174 static const char *dhcp_header_names[] = {
176 "DHCP-Hardware-Type",
177 "DHCP-Hardware-Address-Length",
179 "DHCP-Transaction-Id",
180 "DHCP-Number-of-Seconds",
182 "DHCP-Client-IP-Address",
183 "DHCP-Your-IP-Address",
184 "DHCP-Server-IP-Address",
185 "DHCP-Gateway-IP-Address",
186 "DHCP-Client-Hardware-Address",
187 "DHCP-Server-Host-Name",
188 "DHCP-Boot-Filename",
193 static int dhcp_header_sizes[] = {
203 static void print_hex(RADIUS_PACKET *packet)
206 const uint8_t *p, *a;
208 if (!packet->data) return;
210 if (packet->data_len < 244) {
215 printf("----------------------------------------------------------------------\n");
219 for (i = 0; i < 14; i++) {
220 printf("%s = 0x", dhcp_header_names[i]);
221 for (j = 0; j < dhcp_header_sizes[i]; j++) {
222 printf("%02x", p[j]);
226 p += dhcp_header_sizes[i];
232 printf("%02x %02x %02x %02x\n",
233 p[0], p[1], p[2], p[3]);
236 while (p < (packet->data + packet->data_len)) {
239 if (*p == 255) break; /* end of options signifier */
240 if ((p + 2) > (packet->data + packet->data_len)) break;
242 printf("%02x %02x ", p[0], p[1]);
245 for (i = 0; i < p[1]; i++) {
246 if ((i > 0) && ((i & 0x0f) == 0x00))
248 printf("%02x ", a[i]);
249 if ((i & 0x0f) == 0x0f) printf("\n");
252 if ((p[1] & 0x0f) != 0x00) printf("\n");
256 printf("\n----------------------------------------------------------------------\n");
260 int main(int argc, char **argv)
264 const char *radius_dir = RADDBDIR;
265 const char *filename = NULL;
269 while ((c = getopt(argc, argv, "d:f:hr:t:vx")) != EOF) switch(c) {
277 if (!isdigit((int) *optarg))
279 retries = atoi(optarg);
280 if ((retries == 0) || (retries > 1000)) usage();
283 if (!isdigit((int) *optarg))
285 timeout = atof(optarg);
288 printf("dhclient: $Id$ built on " __DATE__ " at " __TIME__ "\n");
300 argc -= (optind - 1);
301 argv += (optind - 1);
303 if (argc < 2) usage();
305 if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
306 fr_perror("dhclient");
313 server_ipaddr.af = AF_INET;
314 if (strcmp(argv[1], "-") != 0) {
315 const char *hostname = argv[1];
316 const char *portname = argv[1];
319 if (*argv[1] == '[') { /* IPv6 URL encoded */
320 p = strchr(argv[1], ']');
321 if ((size_t) (p - argv[1]) >= sizeof(buffer)) {
325 memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
326 buffer[p - argv[1] - 1] = '\0';
332 p = strchr(portname, ':');
333 if (p && (strchr(p + 1, ':') == NULL)) {
340 if (ip_hton(hostname, AF_INET, &server_ipaddr) < 0) {
341 fprintf(stderr, "dhclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno));
346 * Strip port from hostname if needed.
348 if (portname) server_port = atoi(portname);
352 * See what kind of request we want to send.
354 if (strcmp(argv[2], "discover") == 0) {
355 if (server_port == 0) server_port = 67;
356 packet_code = PW_DHCP_DISCOVER;
358 } else if (strcmp(argv[2], "request") == 0) {
359 if (server_port == 0) server_port = 67;
360 packet_code = PW_DHCP_REQUEST;
362 } else if (isdigit((int) argv[2][0])) {
363 if (server_port == 0) server_port = 67;
364 packet_code = atoi(argv[2]);
366 fprintf(stderr, "Unknown packet type %s\n", argv[2]);
370 request_init(filename);
375 if (!request || !request->vps) {
376 fprintf(stderr, "dhclient: Nothing to send.\n");
379 request->code = packet_code;
382 * Bind to the first specified IP address and port.
383 * This means we ignore later ones.
385 if (request->src_ipaddr.af == AF_UNSPEC) {
386 memset(&client_ipaddr, 0, sizeof(client_ipaddr));
387 client_ipaddr.af = server_ipaddr.af;
390 client_ipaddr = request->src_ipaddr;
391 client_port = request->src_port;
393 sockfd = fr_socket(&client_ipaddr, client_port);
395 fprintf(stderr, "dhclient: socket: %s\n", fr_strerror());
399 request->sockfd = sockfd;
400 if (request->src_ipaddr.af == AF_UNSPEC) {
401 request->src_ipaddr = client_ipaddr;
402 request->src_port = client_port;
404 if (request->dst_ipaddr.af == AF_UNSPEC) {
405 request->dst_ipaddr = server_ipaddr;
406 request->dst_port = server_port;
412 if (fr_dhcp_encode(request, NULL) < 0) {
413 fprintf(stderr, "dhclient: failed encoding: %s\n",
417 if (fr_debug_flag) print_hex(request);
419 if (fr_dhcp_send(request) < 0) {
420 fprintf(stderr, "dhclient: failed sending: %s\n",
425 reply = fr_dhcp_recv(sockfd);
427 fprintf(stderr, "dhclient: no reply\n");
430 if (fr_debug_flag) print_hex(reply);
432 if (fr_dhcp_decode(reply) < 0) {
433 fprintf(stderr, "dhclient: failed decoding\n");
439 if (success) return 0;
444 #endif /* WITH_DHCP */