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