bootpd.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:12k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12. /*
  13.  * BOOTP (bootstrap protocol) server daemon.
  14.  *
  15.  */
  16. #include <stdio.h>
  17. #include <systypes.h>
  18. #include <sysstat.h>
  19. #include <ctype.h>
  20. #include <time.h>
  21. #include "global.h"
  22. #include "config.h"
  23. #include "bootp.h"
  24. #include "cmdparse.h"
  25. #include "iface.h"
  26. #include "mbuf.h"
  27. #include "proc.h"
  28. #include "socket.h"
  29. #include "bootpd.h"
  30. #include "udp.h"
  31. #include "ip.h"
  32. #include "arp.h"
  33. #include "netuser.h"
  34. void bootpd(struct iface *iface, struct udp_cb *sock, int cnt); 
  35. struct udp_cb *Bootpd_cb = NULL;
  36. char homedir[64] = "";       /* bootfile homedirectory */
  37. char defaultboot[64] = "";   /* default file to boot */
  38. struct host hosts[MHOSTS+1];
  39. int Nhosts = 0;    /* current number of hosts */
  40. int32 bp_DefaultDomainNS[BP_MAXDNS] =  {0};
  41. struct bootpd_stat Bootpd_stat;
  42. char *ArpNames[] = {
  43. "Netrom",
  44. "Ethernet",
  45. "AX25",
  46. "Pronet",
  47. "Chaos",
  48. "IEEE 802",
  49. "ArcNet",
  50. "AppleTalk" 
  51. };
  52. /* Routine declarations */
  53. static int bootpd_recv(struct udp_cb *sock,struct bootp *bootp);
  54. static void sendreply(struct bootp *bp,struct iface *iface);
  55. static void vend_fill(uint8 *vend,struct iface *iface,struct host *hp);
  56. static void vend_print(uint8 *vend);
  57. static void bootpd_request(struct bootp *rq,struct iface *iface);
  58. /* The bootp server. */
  59. void 
  60. bootpd(iface,sock,cnt)
  61. struct iface *iface;
  62. struct udp_cb *sock;
  63. int cnt;
  64. {
  65. struct bootp bp_packet;
  66. while(bootpd_recv(sock, &bp_packet) != -1) {
  67.         if(readtab() == -1) /* maybe re-read bootptab */
  68. return;
  69. switch(bp_packet.op) {
  70.      case BOOTREQUEST:
  71. bootpd_request(&bp_packet, iface); 
  72. break;
  73. case BOOTREPLY: 
  74. /* Replies are not forwarded, left to the gateway */ 
  75. break;
  76. }
  77. }
  78. }
  79. /* A packet has been received, read it into a bootp structure. */
  80. static int
  81. bootpd_recv(sock, bootp)
  82. struct udp_cb *sock;
  83. struct bootp *bootp;
  84. {
  85. struct socket fsock;
  86. struct mbuf *bp;
  87. int len;
  88. /* increment the rcvd cnt */
  89. Bootpd_stat.rcvd++;
  90. /* receive the packet */
  91. len = recv_udp(sock,&fsock,&bp);
  92. if(len == -1)
  93. return -1;
  94. /* check length of packet */
  95. if(len < sizeof(struct bootp)) {
  96. Bootpd_stat.bad_size++;
  97. bootp->op = 0;
  98. free_p(&bp);
  99. return -1;
  100. }
  101. /* parse the packet */
  102. pullup (&bp, bootp, sizeof (struct bootp));
  103. free_p(&bp);
  104. if(bootp->op != BOOTREPLY  &&  bootp->op != BOOTREQUEST) {
  105. Bootpd_stat.bad_op++;
  106. bootp->op = 0;
  107. return -1;
  108. }
  109. bootp->ciaddr.s_addr = (unsigned long) get32 ((uint8 *)&(bootp->ciaddr));
  110. bootp->giaddr.s_addr = (unsigned long) get32 ((uint8 *)&(bootp->giaddr));
  111. return 0;
  112. };
  113. /*
  114.  * Process BOOTREQUEST packet.
  115.  *
  116.  * (Note, this version of the bootp.c server never forwards 
  117.  * the request to another server.  In our environment the 
  118.  * stand-alone gateways perform that function.)
  119.  *
  120.  * (Also this version does not interpret the hostname field of
  121.  * the request packet;  it COULD do a name->address lookup and
  122.  * forward the request there.)
  123.  */
  124. static void
  125. bootpd_request (rq, iface)
  126. struct bootp *rq;
  127. struct iface *iface;
  128. {
  129. struct bootp *rp;
  130. char path[64], file[64];
  131. struct host *hp;
  132. int n;
  133. time_t tloc;
  134. int32 ipaddr;
  135. struct arp_type *at;
  136. time(&tloc);
  137. bp_log ("nBootpd request packet received %s", ctime(&tloc));
  138. /* Forwarding not done here. */
  139. if(rq->giaddr.s_addr)  {
  140. bp_log ("     Dropped, giaddr specifies to be forwarded;n");
  141. return;
  142. }
  143. /* Is a specific host requested? */
  144. if((strlen(rq->sname) != 0) && (strcmp (Hostname, rq->sname) != 0)) {
  145. bp_log ("     Dropped, sname specifies server '%s'n", rq->sname);  
  146. return;
  147. }
  148. /* allocate the reply */
  149. rp = (struct bootp *) calloc (1, sizeof (struct bootp));
  150. /* copy for construction */
  151. memcpy (rp, rq, sizeof (struct bootp) - sizeof (rp->vend));
  152. rp->op = BOOTREPLY;
  153. hp = NULL;
  154. /* If the client doesn't know it's ip address, find one. */
  155. if(rq->ciaddr.s_addr == 0) { 
  156. /*
  157.  * client doesn't know his IP address, 
  158.  * search by hardware address.
  159.  */
  160. at = &Arp_type[rq->htype];
  161. bp_log ("     Resolved by %s addr %sn", ArpNames[rq->htype], 
  162. (*at->format)(bp_ascii, rq->chaddr));
  163. for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  164. if((rq->htype == hp->htype)
  165.    && (memcmp(rq->chaddr, hp->haddr, rq->hlen) == 0))
  166. break;
  167. /* If the client wasn't found, assign an IP address */
  168. if(n == Nhosts) {
  169. hp = NULL;
  170. if(da_assign(iface, rq->chaddr, &ipaddr) != 0) {
  171. free (rp);
  172. bp_log ("     No dynamic addresses available.n");
  173. return;
  174. } else {
  175. put32 ((uint8 *) &(rp->yiaddr), ipaddr);
  176. bp_log ("     Dynamic address assigned: %sn", 
  177. inet_ntoa (ipaddr));
  178. }
  179. } else {
  180. bp_log ("     Static address assigned: %sn", 
  181. inet_ntoa (hp->iaddr.s_addr));
  182. put32 ((uint8 *) &(rp->yiaddr), hp->iaddr.s_addr);
  183. }
  184. } else {
  185. /* search by IP address */
  186. bp_log ("     Resolve by IP addr %sn", inet_ntoa (rq->ciaddr.s_addr));
  187. for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  188. if(rq->ciaddr.s_addr == hp->iaddr.s_addr)
  189. break;
  190. if(n == Nhosts) {
  191. hp = NULL;
  192. bp_log ("     Host not found, default values used.n");
  193. } else
  194. bp_log ("     Lookup successful.n");
  195. put32 ((uint8 *) &(rp->ciaddr), rq->ciaddr.s_addr);
  196. }
  197. put32 ((uint8 *) &(rp->siaddr), iface->addr);
  198. /* Determine the bootp file */
  199. file[0] = 0;
  200. if(rq->file[0] == 0) {  /* if client didn't specify file */
  201. /* Use the host record file, else the default file */
  202. if((hp == NULL) || (hp->bootfile[0] == 0))
  203. strcpy(file, defaultboot);
  204. else
  205. strcpy(file, hp->bootfile);
  206. } else {
  207. /* use client specified file */
  208. strcpy(file, rq->file);
  209. }
  210. /* If a file is specified, specify the path to the bootp file */
  211. path[0] = 0;
  212. if((*homedir != 0) && (*file != 0)) {
  213. strcpy(path, homedir);
  214. strcat(path, "/");
  215. }
  216. if(file[0] == '/')     /* if absolute pathname */
  217. strcpy(path, file);
  218. else
  219. strcat(path, file);
  220. /* No files are provided here, just return a path. */
  221. strcpy(rp->file, path);
  222. /* Fill in the vendor information */
  223. vend_fill (rp->vend, iface, hp);
  224. sendreply (rp, iface);
  225. free (rp); 
  226. };
  227. /* Print the bootp structure. */
  228. void
  229. bootp_print_packet  (bp)
  230. struct bootp *bp;
  231. {
  232. bp_log ("Packet op code........................%dn", bp->op);
  233. bp_log ("hardware address type.................%dn", bp->htype);
  234. bp_log ("hardware address length...............%dn", bp->hlen);
  235. bp_log ("client sets to zero...................%dn", bp->hops);
  236. bp_log ("transaction ID........................%ldn", bp->xid);
  237. bp_log ("seconds elapsed since client booted...%dn", bp->secs);
  238. bp_log ("unused................................%dn", bp->unused);
  239. bp_log ("Client IP address, if known...........%sn",
  240. inet_ntoa ((int32)bp->ciaddr.s_addr));
  241. bp_log ("Server supplied IP address............%sn", 
  242. inet_ntoa ((int32)bp->yiaddr.s_addr));
  243. bp_log ("Server IP address.....................%sn", 
  244. inet_ntoa ((int32)bp->siaddr.s_addr));
  245. bp_log ("Gateway IP address....................%sn", 
  246. inet_ntoa ((int32)bp->giaddr.s_addr));
  247. bp_log ("Client hardware address...............%x:%x:%x:%x:%x:%xn",
  248. bp->chaddr[0], bp->chaddr[1], bp->chaddr[2],
  249. bp->chaddr[3], bp->chaddr[4], bp->chaddr[5]);
  250. bp_log ("Server host name......................'%s'n", bp->sname);
  251. bp_log ("Boot file name........................'%s'n", bp->file);
  252. vend_print (bp->vend);
  253. }
  254. static void
  255. vend_print (vend)
  256. uint8 *vend; 
  257. {
  258. uint8 ch;
  259. int size;
  260. uint8 *start;
  261. int32 *ipaddr;
  262. int i;
  263. start = vend;
  264. bp_log ("Magic Cookie..........................x%02x%02x%02x%02xn", 
  265. (int) vend[0], (int) vend[1], (int) vend[2], (int) vend[3]);
  266. vend = vend + 4;
  267. while(((ch = *vend++) != BOOTP_END) && (vend - start <= 64)) 
  268. switch(ch) {
  269. case BOOTP_PAD:  /* They're just padding */
  270. continue;
  271. case BOOTP_SUBNET:      /* fixed length, 4 octets */
  272. size = (int) *vend++;
  273. ipaddr = (int32 *) vend;
  274. bp_log ("Vend Subnet...........................%sn", inet_ntoa
  275. (*ipaddr));
  276. vend += size;
  277. break;
  278. case BOOTP_HOSTNAME:
  279. size = (int) *vend++;
  280. bp_log ("Vend Hostname.........................%sn", vend);
  281. vend += size;
  282. break;
  283. case BOOTP_DNS:
  284. size = (int) *vend++;
  285. for(i = 0; i < (size / 4); i++) {
  286. ipaddr = (int32 *) vend;
  287. bp_log ("Vend DomainNS.........................%sn", 
  288. inet_ntoa (*ipaddr));
  289. vend += 4;
  290. }
  291. break;
  292. case BOOTP_GATEWAY:
  293. size = (int) *vend++;
  294. for(i = 0; i < (size / 4); i++) {
  295. ipaddr = (int32 *) vend;
  296. bp_log ("Vend Gateway..........................%sn", 
  297. inet_ntoa (*ipaddr));
  298. vend += 4;
  299. }
  300. break;
  301. default: /* variable field we don't know about */
  302. size = *vend++;
  303. vend += size;
  304. break;
  305. }
  306. }
  307. static void
  308. vend_fill (vend, iface, hp)
  309. uint8 *vend;
  310. struct iface *iface;
  311. struct host *hp;
  312. {
  313. uint8  cookie[5] = {99, 130, 83, 99, 0};
  314. int  len;
  315. int mod;
  316. int i;
  317. uint8 *sizep;
  318. /* Magic cookie */
  319. memcpy(vend,cookie,4);
  320. vend += 4;
  321. /* Send the iface subnet */
  322. /* Pad so number falls on word boundry */
  323. vend++;
  324. vend++;
  325. *vend = BOOTP_SUBNET;
  326. vend++;
  327. *vend = 4;
  328. vend++;
  329. put32 (vend, iface->netmask);
  330. vend += 4;
  331. /* Send the DNS */
  332. if(bp_DefaultDomainNS[0] != 0) {
  333. /* Pad for allignment */
  334. vend++;
  335. vend++;
  336. *vend = BOOTP_DNS;
  337. vend++;
  338. sizep = vend;
  339. vend++;
  340. for(i = 0; (i < BP_MAXDNS) && (bp_DefaultDomainNS[i] != 0); i++) {
  341. put32 (vend, bp_DefaultDomainNS[i]);
  342. *sizep = *sizep + 4;
  343. vend += 4;
  344. }
  345. }
  346. /* Send the default gateway */
  347. if(R_default.iface == iface) {
  348. vend++;
  349. vend++;
  350. *vend = BOOTP_GATEWAY; 
  351. vend++;
  352. *vend = 4;
  353. vend++;
  354. put32 (vend, R_default.gateway);
  355. vend +=  4;
  356. }
  357. /* Send the hostname */
  358. if(hp != NULL) {
  359. /* Pad so name begins on a word boundry */
  360. vend++;
  361. vend++;
  362. *vend = BOOTP_HOSTNAME;
  363. vend++;
  364. *vend = len = strlen (hp->name) + 1;
  365. vend++;
  366. strcpy ((char *)vend, hp->name);
  367. vend += len;
  368. /* Pad to a word. */
  369. mod = 4 - (len % 4);
  370. for(i = 0; i < mod; i++) {
  371. *vend = BOOTP_PAD;
  372. vend++;
  373. }
  374. }
  375. /* Mark the end of the data */
  376. *vend = BOOTP_END;
  377. }
  378. /*
  379.  * Send a reply packet to the client.  'forward' flag is set if we are
  380.  * not the originator of this reply packet.
  381.  */
  382. static void
  383. sendreply(bp, iface)
  384. struct bootp *bp;
  385. struct iface *iface;
  386. {
  387. struct mbuf *buf;
  388. int32 faddr;
  389. uint16 length;
  390. uint8 *cp;
  391. /*
  392.  * If the client IP address is specified, use that
  393.  * else if gateway IP address is specified, use that
  394.  * else make a temporary arp cache entry for the client's NEW 
  395.  * IP/hardware address and use that.
  396.  */
  397. if(bp->ciaddr.s_addr) {
  398. faddr = get32 ((uint8 *) &(bp->ciaddr));
  399. } else {
  400. faddr = get32 ((uint8 *) &(bp->yiaddr));
  401. arp_add (faddr, (uint16) bp->htype, bp->chaddr, 0);
  402. }
  403. if((buf = qdata (bp, sizeof (struct bootp))) == NULL)
  404. return;
  405. pushdown (&buf, NULL,UDPHDR);
  406. length = sizeof (struct bootp) + UDPHDR;
  407. cp = buf->data;
  408. cp = put16 (cp, IPPORT_BOOTPS); /* Source */
  409. cp = put16 (cp, IPPORT_BOOTPC); /* Dest */
  410. cp = put16 (cp, length);
  411. *cp++ = 0;
  412. *cp = 0;
  413. ip_send (iface->addr, faddr, UDP_PTCL, 0, 0, &buf, length, 0, 0);
  414. };