ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/dhcpping/dhcping.c
Revision: 1.1
Committed: Mon Jul 26 00:46:09 2004 UTC (19 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 //
2 // $Id: dhcping.c,v 1.3 2002/01/27 01:57:15 mavetju Exp $
3 //
4
5 /*
6 * Copyright 2000, 2001, 2002 by Edwin Groothuis, edwin@mavetju.org
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <sys/uio.h>
35 #include <netinet/in.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42
43 #include "dhcp_options.h"
44
45 #define BUF_SIZ 256*256
46 #define MAX_OPTIONS 256
47 #define MAX_DATA 256
48
49 int offset=0;
50 void addpacket(char *pktbuf,char *msgbuf,int size) {
51 memcpy(pktbuf+offset,msgbuf,size);
52 offset+=size;
53 }
54
55 void dhcp_setup(char *);
56 int dhcp_read(void);
57 void dhcp_close(void);
58 void dhcp_dump(unsigned char *buffer,int size);
59 void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware);
60 void dhcp_request(char *ipaddr,char *gwaddr,char *hardware);
61 void dhcp_release(char *ipaddr,char *gwaddr,char *hardware);
62 void dhcp_packet(int type,char *ciaddr,char *opt50,char *gwaddr,char *hardware);
63
64 int dhcp_socket;
65 struct sockaddr_in dhcp_to;
66
67 int _serveripaddress;
68
69 int inform,request,verbose,VERBOSE,quiet;
70 char *ci,*gi,*server,*hw;
71 unsigned char serveridentifier[4];
72 int maxwait=3;
73
74 typedef struct optpack cmdlineopt;
75
76 struct optpack {
77 unsigned int option;
78 char data[MAX_DATA];
79 } cmdlineopts[MAX_OPTIONS];
80
81 char sname[64];
82 unsigned int opt = 0;
83
84 void doargs(int argc,char **argv) {
85 char ch;
86
87 inform=request=verbose=VERBOSE=quiet=0;
88 ci=gi=server="0.0.0.0";
89 hw="00:00:00:00:00:00";
90
91 if (argc==1) {
92 printf("dhcping -S sname -c ciaddr -g giaddr -h chaddr -r -s server -t maxwait -i -v -q -o option:data\n");
93 exit(1);
94 }
95
96 while ((ch = getopt(argc,argv,"c:o:S:g:h:iqrs:t:vV"))>0) {
97 switch (ch) {
98 case 'c': ci=optarg;break;
99 case 'g': gi=optarg;break;
100 case 'h': hw=optarg;break;
101 case 'i': inform=1;break;
102 case 'q': quiet=1;break;
103 case 'r': request=1;break;
104 case 's': server=optarg;break;
105 case 't': maxwait=atoi(optarg);break;
106 case 'v': verbose=1;break;
107 case 'V': VERBOSE=1;break;
108 case 'o': if (opt > MAX_OPTIONS) {
109 printf ("Exceeded maximum options parameter(%d).\n", MAX_OPTIONS);
110 break;
111 }
112 char x[100+MAX_DATA];
113 sprintf (x, "%%d:%%%ds", MAX_DATA);
114 sscanf (optarg, x, &cmdlineopts[opt].option, cmdlineopts[opt].data);
115 printf ("optarg: %s, opt: %d, cmd1: %d, cmd2: %s, x: %s"
116 , optarg, opt, cmdlineopts[opt].option, cmdlineopts[opt++].data, x);
117 break;
118 case 'S': sscanf (optarg, "%63s", sname);break;
119 }
120 }
121
122 if (request && inform) {
123 fprintf(stderr,"Error: -r and -i are mutally exclusive.\n");
124 exit(1);
125 }
126
127 // DHCPREQUEST is by default.
128 if (!inform) request=1;
129 }
130
131 int main(int argc,char **argv) {
132 fd_set read;
133 struct timeval timeout;
134 int foundpacket=0;
135 int returnvalue=0;
136
137 if (geteuid()!=0) {
138 printf("This program should only be run by root or be installed as setuid root.\n");
139 exit(1);
140 }
141
142 doargs(argc,argv);
143
144 if (VERBOSE) puts("setup");
145 dhcp_setup(server);
146
147 if (setuid(getuid())!=0) {
148 perror("setuid");
149 printf("Can't drop privileges back to normal user, program aborted.\n");
150 exit(1);
151 }
152
153 if (inform) {
154 if (VERBOSE) puts("inform");
155 dhcp_inform(ci,gi,hw);
156 }
157 if (request) {
158 if (VERBOSE) puts("request");
159 dhcp_request(ci,gi,hw);
160 }
161
162 while (!foundpacket) {
163 FD_ZERO(&read);
164 FD_SET(dhcp_socket,&read);
165 timeout.tv_sec=maxwait;
166 timeout.tv_usec=0;
167 if(select(dhcp_socket+1,&read,NULL,NULL,&timeout)<0) {
168 perror("select");
169 exit(0);
170 }
171 if (FD_ISSET(dhcp_socket,&read)) {
172 if (VERBOSE) puts("read");
173 /* If a expected packet was found, then also release it. */
174 if ((foundpacket=dhcp_read())!=0) {
175 if (request) {
176 if (VERBOSE) puts("release");
177 dhcp_release(ci,gi,hw);
178 }
179 }
180 } else {
181 if (!quiet)
182 fprintf(stderr,"no answer\n");
183 returnvalue=1;
184 foundpacket=1;
185 }
186 }
187 if (VERBOSE) puts("close");
188 dhcp_close();
189 return returnvalue;
190 }
191
192
193 void dhcp_setup(char *serveripaddress) {
194 struct servent *servent,*clientent;
195 struct hostent *hostent;
196 int flag;
197 struct sockaddr_in name;
198
199 /*
200 // setup sending socket
201 */
202 if ((servent=getservbyname("bootps",0))==NULL) {
203 perror("getservbyname: bootps");
204 exit(1);
205 }
206 if ((hostent=gethostbyname(serveripaddress))==NULL) {
207 perror("gethostbyname");
208 exit(1);
209 }
210
211 dhcp_to.sin_family=AF_INET;
212 bcopy(hostent->h_addr,&dhcp_to.sin_addr.s_addr,hostent->h_length);
213 _serveripaddress=ntohl(dhcp_to.sin_addr.s_addr);
214 /* dhcp_to.sin_addr.s_addr=INADDR_BROADCAST; */
215 dhcp_to.sin_port=servent->s_port;
216
217 if ((dhcp_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) {
218 perror("dhcp_socket/socket");
219 exit(1);
220 }
221
222 flag=1;
223 if (setsockopt (dhcp_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) {
224 perror("dhcp_socket/setsockopt: SO_REUSEADDR");
225 exit(1);
226 }
227
228 if (setsockopt(dhcp_socket,SOL_SOCKET,SO_BROADCAST,(char *)&flag, sizeof flag) < 0) {
229 perror ("dhcp_socket/setsockopt: SO_BROADCAST");
230 exit(1);
231 }
232
233 if ((clientent=getservbyname("bootpc",0))==NULL) {
234 perror("getservbyname: bootpc");
235 exit(1);
236 }
237 name.sin_family = AF_INET;
238 name.sin_port = clientent->s_port;
239 name.sin_addr.s_addr = INADDR_ANY;
240 /* name.sin_addr.s_addr = INADDR_NONE; */
241 memset (name.sin_zero, 0, sizeof (name.sin_zero));
242
243 if (bind (dhcp_socket, (struct sockaddr *)&name, sizeof name) < 0) {
244 perror("bind");
245 exit(1);
246 }
247 }
248
249 void dhcp_request(char *ipaddr,char *gwaddr,char *hardware) {
250 dhcp_packet(3,ipaddr,ipaddr,gwaddr,hardware);
251 }
252 void dhcp_release(char *ipaddr,char *gwaddr,char *hardware) {
253 dhcp_packet(7,ipaddr,NULL,gwaddr,hardware);
254 }
255 void dhcp_inform(char *ipaddr,char *gwaddr,char *hardware) {
256 dhcp_packet(8,ipaddr,NULL,gwaddr,hardware);
257 }
258
259
260 void dhcp_packet(int type,char *ipaddr,char *opt50,char *gwaddr,char *hardware) {
261 static time_t l=0;
262 unsigned char msgbuf[BUF_SIZ];
263 unsigned char pktbuf[BUF_SIZ];
264 int ip[4],gw[4],hw[16],ip50[4];
265 int hwcount;
266
267 sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]);
268 sscanf(gwaddr,"%d.%d.%d.%d",&gw[0],&gw[1],&gw[2],&gw[3]);
269 if (opt50)
270 sscanf(opt50,"%d.%d.%d.%d",&ip50[0],&ip50[1],&ip50[2],&ip50[3]);
271 memset(&hw,0,sizeof(hw));
272 hwcount=sscanf(hardware,"%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
273 &hw[0],&hw[1],&hw[2],&hw[3],
274 &hw[4],&hw[5],&hw[6],&hw[7],
275 &hw[8],&hw[9],&hw[10],&hw[11],
276 &hw[12],&hw[13],&hw[14],&hw[15]);
277
278 memset(msgbuf,0,sizeof(msgbuf));
279 sprintf(msgbuf,"\1\1%c%c",hwcount,0);
280 addpacket(pktbuf,msgbuf,4);
281
282 /* xid */
283 if (l>time(NULL))
284 l++;
285 else
286 l=time(NULL);
287 memcpy(msgbuf,&l,4);
288 addpacket(pktbuf,msgbuf,4);
289
290 /* secs and flags */
291 memset(msgbuf,0,4);
292 addpacket(pktbuf,msgbuf,4);
293 /* sprintf(msgbuf,"%c%c",0x80,0x00); */
294 /* sprintf(msgbuf,"%c%c",0x00,0x00); */
295 /* addpacket(pktbuf,msgbuf,2); */
296
297 /* ciaddr */
298 memset(msgbuf,0,4);
299 sprintf(msgbuf,"%c%c%c%c",ip[0],ip[1],ip[2],ip[3]);
300 addpacket(pktbuf,msgbuf,4);
301
302 /* yiaddr */
303 memset(msgbuf,0,4);
304 addpacket(pktbuf,msgbuf,4);
305
306 /* siaddr */
307 memset(msgbuf,0,4);
308 addpacket(pktbuf,msgbuf,4);
309
310 /* giaddr */
311 sprintf(msgbuf,"%c%c%c%c",gw[0],gw[1],gw[2],gw[3]);
312 addpacket(pktbuf,msgbuf,4);
313
314 /* chaddr */
315 sprintf(msgbuf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
316 hw[0],hw[1],hw[2],hw[3],hw[4],hw[5],hw[6],hw[7],
317 hw[8],hw[9],hw[10],hw[11],hw[12],hw[13],hw[14],hw[15]);
318 addpacket(pktbuf,msgbuf,16);
319
320 /* sname */
321 memset(msgbuf,0,64);
322 printf("hallo!!!\n");
323 if (strlen (sname) > 0) {
324 sprintf (msgbuf, "%s", sname);
325 }
326 addpacket(pktbuf,msgbuf,64);
327
328 /* file */
329 memset(msgbuf,0,128);
330 addpacket(pktbuf,msgbuf,128);
331
332 /* options */
333 {
334 /* cookie */
335 sprintf(msgbuf,"%c%c%c%c",99,130,83,99);
336 addpacket(pktbuf,msgbuf,4);
337
338 /* dhcp-type */
339 sprintf(msgbuf,"%c%c%c",53,1,type);
340 addpacket(pktbuf,msgbuf,3);
341
342 /* Not for inform */
343 if (type!=8) {
344 /* requested IP address */
345 if (opt50) {
346 sprintf(msgbuf,"%c%c%c%c%c%c",50,4,ip50[0],ip50[1],ip50[2],ip50[3]);
347 addpacket(pktbuf,msgbuf,6);
348 }
349
350 /* server-identifier */
351 if (serveridentifier[0]) {
352 sprintf(msgbuf,"%c%c%c%c%c%c",54,4,
353 serveridentifier[0],serveridentifier[1],
354 serveridentifier[2],serveridentifier[3]);
355 addpacket(pktbuf,msgbuf,6);
356 }
357 /* command line options */
358 while (opt--) {
359 sprintf (msgbuf, "%c%c%s", cmdlineopts[opt].option, (char *)(strlen (cmdlineopts[opt].data) + 1), cmdlineopts[opt].data);
360 addpacket(pktbuf, msgbuf, 2 + strlen (cmdlineopts[opt].data) + 1);
361 }
362 }
363
364 /* client-identifier */
365 // sprintf(msgbuf,"%c%c%c%c%c%c%c%c",61,6,
366 // hw[0],hw[1],hw[2],hw[3],hw[4],hw[5]);
367 // addpacket(pktbuf,msgbuf,8);
368
369 /* parameter request list */
370 if (type==8) {
371 sprintf(msgbuf,"%c%c%c",55,1,1);
372 addpacket(pktbuf,msgbuf,3);
373 }
374
375 /* end of options */
376 sprintf(msgbuf,"%c",255);
377 addpacket(pktbuf,msgbuf,1);
378 }
379
380 dhcp_dump(pktbuf,offset);
381
382 sendto(dhcp_socket,pktbuf,offset,0,(struct sockaddr *)&dhcp_to,sizeof(dhcp_to));
383
384 offset=0;
385 }
386
387
388 int dhcp_read(void) {
389 unsigned char msgbuf[BUF_SIZ];
390 struct sockaddr_in fromsock;
391 socklen_t fromlen=sizeof(fromsock);
392 int addr;
393 int i;
394
395 i=recvfrom(dhcp_socket,msgbuf,BUF_SIZ,0,(struct sockaddr *)&fromsock,&fromlen);
396 addr=ntohl(fromsock.sin_addr.s_addr);
397
398 if (!quiet) {
399 printf( "Got answer from: %d.%d.%d.%d\n",
400 ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
401 ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF
402 );
403 }
404
405 if (_serveripaddress!=addr) {
406 if (!quiet)
407 fprintf(stderr,"received from %d.%d.%d.%d, expected from %d.%d.%d.%d\n",
408 ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
409 ( addr >> 8 ) & 0xFF, ( addr ) & 0xFF,
410 ( _serveripaddress >> 24 )&0xFF,(_serveripaddress >> 16 )&0xFF,
411 ( _serveripaddress >> 8 )&0xFF,(_serveripaddress )&0xFF
412 );
413 return 0;
414
415 }
416
417
418 dhcp_dump(msgbuf,i);
419 return 1;
420 }
421
422
423
424 void dhcp_dump(unsigned char *buffer,int size) {
425 int j;
426
427 if (VERBOSE)
428 printf("packet %d bytes\n",size);
429
430 if (!VERBOSE)
431 return;
432
433 //
434 // Are you sure you want to see this? Try dhcpdump, which is better
435 // suited for this kind of work... See http://www.mavetju.org
436 //
437 j=0;
438 while (j<size) {
439 printf("%02x ",buffer[j]);
440 if (j%16==15) printf("\n");
441 j++;
442 }
443 printf("\n");
444
445 printf("op: %d\n",buffer[0]);
446 printf("htype: %d\n",buffer[1]);
447 printf("hlen: %d\n",buffer[2]);
448 printf("hops: %d\n",buffer[3]);
449
450 printf("xid: %02x%02x%02x%02x\n",
451 buffer[4],buffer[5],buffer[6],buffer[7]);
452 printf("secs: %d\n",255*buffer[8]+buffer[9]);
453 printf("flags: %x\n",255*buffer[10]+buffer[11]);
454
455 printf("ciaddr: %d.%d.%d.%d\n",
456 buffer[12],buffer[13],buffer[14],buffer[15]);
457 printf("yiaddr: %d.%d.%d.%d\n",
458 buffer[16],buffer[17],buffer[18],buffer[19]);
459 printf("siaddr: %d.%d.%d.%d\n",
460 buffer[20],buffer[21],buffer[22],buffer[23]);
461 printf("giaddr: %d.%d.%d.%d\n",
462 buffer[24],buffer[25],buffer[26],buffer[27]);
463 printf("chaddr: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
464 buffer[28],buffer[29],buffer[30],buffer[31],
465 buffer[32],buffer[33],buffer[34],buffer[35],
466 buffer[36],buffer[37],buffer[38],buffer[39],
467 buffer[40],buffer[41],buffer[42],buffer[43]);
468 printf("sname : %s.\n",buffer+44);
469 printf("fname : %s.\n",buffer+108);
470
471 j=236;
472 j+=4; /* cookie */
473 while (j<size && buffer[j]!=255) {
474 printf("option %d %s\n",buffer[j],dhcp_options[buffer[j]]);
475
476 switch (buffer[j]) {
477 case 1:
478 printf("\tSubnet mask: %d.%d.%d.%d\n",
479 buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
480 break;
481 case 3:
482 printf("\tRouter: %d.%d.%d.%d\n",
483 buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
484 break;
485 case 50:
486 printf("\tRequested IP address: %d.%d.%d.%d\n",
487 buffer[j+2],buffer[j+3],buffer[j+4],buffer[j+5]);
488 break;
489 case 53:
490 printf("\tDHCP message type: %d (%s)\n",
491 buffer[j+2],dhcp_message_types[buffer[j+2]]);
492 break;
493 case 54:
494 memcpy(serveridentifier,buffer+j+2,4);
495 printf("\tServer identifier: %d.%d.%d.%d\n",
496 serveridentifier[0],serveridentifier[1],
497 serveridentifier[2],serveridentifier[3]);
498 break;
499 case 61:
500 printf("\tClient identifier: %02x%02x%02x%02x%02x%02x\n",
501 buffer[j+2],buffer[j+3],buffer[j+4],
502 buffer[j+5],buffer[j+6],buffer[j+7]);
503 break;
504 }
505
506 /*
507 // This might go wrong if a mallformed packet is received.
508 // Maybe from a bogus server which is instructed to reply
509 // with invalid data and thus causing an exploit.
510 // My head hurts... but I think it's solved by the checking
511 // for j<size at the begin of the while-loop.
512 */
513 j+=buffer[j+1]+2;
514 }
515 }
516
517
518 void dhcp_close(void) {
519 close(dhcp_socket);
520 }
521