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

TCP/IP协议栈

开发平台:

Visual C++

  1. /* This file contains code to implement the Routing Information Protocol (RIP)
  2.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  3.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  4.  * credited. (Well, here's some credit :-). AGB 4-28-88
  5.  * Further documentation on the RIP protocol is now available in Charles
  6.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  7.  *
  8.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  9.  *
  10.  * Code gutted and substantially rewritten. KA9Q 9/89
  11.  */
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "netuser.h"
  15. #include "udp.h"
  16. #include "timer.h"
  17. #include "iface.h"
  18. #include "ip.h"
  19. #include "internet.h"
  20. #include "rip.h"
  21. #include "arp.h"
  22. struct rip_stat Rip_stat;
  23. uint16 Rip_trace;
  24. int Rip_merge;
  25. struct rip_list *Rip_list;
  26. struct udp_cb *Rip_cb;
  27. struct rip_refuse *Rip_refuse;
  28. static void rip_rx(struct iface *iface,struct udp_cb *sock,int cnt);
  29. static void proc_rip(struct iface *iface,int32 gateway,
  30. struct rip_route *ep,int32 ttl);
  31. static uint8 *putheader(uint8 *cp,enum ripcmd command,uint8 version);
  32. static uint8 *putentry(uint8 *cp,uint16 fam,int32 target,int32 metric);
  33. static void rip_shout(void *p);
  34. static void send_routes(int32 dest,uint16 port,int split,int trig,
  35. int us);
  36. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  37. static void
  38. rip_shout(p)
  39. void *p;
  40. {
  41. register struct rip_list *rl;
  42. rl = (struct rip_list *)p;
  43. stop_timer(&rl->rip_time);
  44. send_routes(rl->dest,RIP_PORT,rl->flags.rip_split,0,rl->flags.rip_us);
  45. set_timer(&rl->rip_time,rl->interval*1000L);
  46. start_timer(&rl->rip_time);
  47. }
  48. /* Send the routing table. */
  49. static void
  50. send_routes(dest,port,split,trig,us)
  51. int32 dest; /* IP destination address to send to */
  52. uint16 port;
  53. int split; /* Do split horizon? */
  54. int trig; /* Send only triggered updates? */
  55. int us; /* Include our address in update */
  56. {
  57. uint8 *cp;
  58. int i,bits,numroutes,maxroutes;
  59. uint16 pktsize;
  60. struct mbuf *bp;
  61. struct route *rp;
  62. struct socket lsock,fsock;
  63. struct iface *iface;
  64. if((rp = rt_lookup(dest)) == NULL)
  65. return; /* No route exists, can't do it */
  66. iface = rp->iface;
  67. /* Compute maximum packet size and number of routes we can send */
  68. pktsize = ip_mtu(dest) - IPLEN;
  69. pktsize = min(pktsize,MAXRIPPACKET);
  70. maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
  71. lsock.address = INADDR_ANY;
  72. lsock.port = RIP_PORT;
  73. fsock.address = dest;
  74. fsock.port = port;
  75. /* Allocate space for a full size RIP packet and generate header */
  76. if((bp = alloc_mbuf(pktsize)) == NULL)
  77. return; 
  78. numroutes = 0;
  79. cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  80. /* Emit route to ourselves, if requested */
  81. if(us){
  82. cp = putentry(cp,RIP_IPFAM,iface->addr,1);
  83. numroutes++;
  84. }
  85. /* Emit default route, if appropriate */
  86. if(R_default.iface != NULL && !R_default.flags.rtprivate
  87.  && (!trig || R_default.flags.rttrig)){
  88. if(!split || iface != R_default.iface){
  89.   cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
  90. numroutes++;
  91. } else if(trig){
  92. cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
  93. numroutes++;
  94. }
  95. }
  96. for(bits=0;bits<32;bits++){
  97. for(i=0;i<HASHMOD;i++){
  98. for(rp = Routes[bits][i];rp != NULL;rp=rp->next){
  99. if(rp->flags.rtprivate
  100.  || (trig && !rp->flags.rttrig)) 
  101. continue;
  102. if(numroutes >= maxroutes){
  103. /* Packet full, flush and make another */
  104. bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  105. send_udp(&lsock,&fsock,0,0,&bp,bp->cnt,0,0);
  106. Rip_stat.output++;
  107. if((bp = alloc_mbuf(pktsize)) == NULL)
  108. return; 
  109. numroutes = 0;
  110. cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  111. }
  112. if(!split || iface != rp->iface){
  113.   cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric+1);
  114. numroutes++;
  115. } else if(trig){
  116.   cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
  117. numroutes++;
  118. }
  119. }
  120. }
  121. }
  122. if(numroutes != 0){
  123. bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  124. send_udp(&lsock,&fsock,0,0,&bp,bp->cnt,0,0);
  125. Rip_stat.output++;
  126. } else {
  127. free_p(&bp);
  128. }
  129. }
  130. /* Add an entry to the rip broadcast list */
  131. int
  132. rip_add(dest,interval,split,us)
  133. int32 dest;
  134. int32 interval;
  135. int split,us;
  136. {
  137. register struct rip_list *rl;
  138. struct route *rp;
  139. if((rp = rt_lookup(dest)) == NULL){
  140. printf("%s is unreachablen",inet_ntoa(dest));
  141. return 1;
  142. }
  143. for(rl = Rip_list; rl != NULL; rl = rl->next)
  144. if(rl->dest == dest)
  145. break;
  146. if(rl == NULL){
  147. /* get a chunk of memory for the rip interface descriptor */
  148. rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  149. /* tack this record on as the first in the list */
  150. rl->next = Rip_list;
  151. if(rl->next != NULL)
  152. rl->next->prev = rl;
  153. Rip_list = rl;
  154. rl->dest = dest;
  155. }
  156. /* and the interface ptr, tick interval and flags */
  157. rl->iface = rp->iface;
  158. rl->interval = interval;
  159. rl->flags.rip_split = split;
  160. rl->flags.rip_us = us;
  161. /* set up the timer stuff */
  162. rl->rip_time.func = rip_shout;
  163. rl->rip_time.arg = rl;
  164. /* This will initialize the timer and do an immediate broadcast */
  165. rip_shout(rl);
  166. return 0;
  167. }
  168. /* add a gateway to the rip_refuse list which allows us to ignore their
  169.  * advertisements
  170. */
  171. int
  172. riprefadd(gateway)
  173. int32 gateway;
  174. {
  175. register struct rip_refuse *rl;
  176. for(rl = Rip_refuse; rl != NULL; rl = rl->next)
  177. if(rl->target == gateway)
  178. return 0; /* Already in table */
  179.   
  180. /* get a chunk of memory for the rip interface descriptor */
  181. rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  182. /* tack this record on as the first in the list */
  183. rl->next = Rip_refuse;
  184. if(rl->next != NULL)
  185. rl->next->prev = rl;
  186. Rip_refuse = rl;
  187. /* fill in the gateway to ignore */
  188. rl->target = gateway;
  189. return 0;
  190. }
  191. /* drop a RIP target */
  192. int
  193. rip_drop(dest)
  194. int32 dest;
  195. {
  196. register struct rip_list *rl;
  197. for(rl = Rip_list; rl != NULL; rl = rl->next)
  198. if(rl->dest == dest)
  199. break;
  200. /* leave if we didn't find it */
  201. if(rl == NULL)
  202. return 0;
  203. /* stop the timer */
  204. stop_timer(&rl->rip_time);
  205. /* Unlink from list */
  206. if(rl->next != NULL)
  207. rl->next->prev = rl->prev;
  208. if(rl->prev != NULL)
  209. rl->prev->next = rl->next;
  210. else
  211. Rip_list = rl->next;
  212. /* and deallocate the descriptor memory */
  213. free(rl);
  214. return 0;
  215. }
  216. /* drop a RIP-refuse target from the rip_refuse list */
  217. int
  218. riprefdrop(gateway)
  219. int32 gateway;
  220. {
  221. register struct rip_refuse *rl;
  222. for(rl = Rip_refuse; rl != NULL; rl = rl->next)
  223. if(rl->target == gateway)
  224. break;
  225.   
  226. /* leave if we didn't find it */
  227. if(rl == NULL)
  228. return 0;
  229. /* Unlink from list */
  230. if(rl->next != NULL)
  231. rl->next->prev = rl->prev;
  232. if(rl->prev != NULL)
  233. rl->prev->next = rl->next;
  234. else
  235. Rip_refuse = rl->next;
  236. /* and deallocate the structure memory */
  237. free(rl);
  238. return 0;
  239. }
  240. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  241. void
  242. rip_trigger()
  243. {
  244. register struct rip_list *rl;
  245. int bits,i;
  246. struct route *rp;
  247. for(rl=Rip_list;rl != NULL;rl = rl->next){
  248. send_routes(rl->dest,RIP_PORT,rl->flags.rip_split,1,0);
  249. }
  250. /* Clear the trigger list */
  251. R_default.flags.rttrig = 0;
  252. for(bits=0;bits<32;bits++){
  253. for(i=0;i<HASHMOD;i++){
  254. for(rp = Routes[bits][i];rp != NULL;rp = rp->next){
  255. rp->flags.rttrig = 0;
  256. }
  257. }
  258. }
  259. }
  260. /* Start RIP agent listening at local RIP UDP port */
  261. int
  262. rip_init()
  263. {
  264. struct socket lsock;
  265. lsock.address = INADDR_ANY;
  266. lsock.port = RIP_PORT;
  267. if(Rip_cb == NULL)
  268. Rip_cb = open_udp(&lsock,rip_rx);
  269. return 0;
  270. }
  271. /* Process RIP input received from 'interface'. */
  272. static void
  273. rip_rx(iface,sock,cnt)
  274. struct iface *iface;
  275. struct udp_cb *sock;
  276. int cnt;
  277. {
  278. struct mbuf *bp;
  279. struct socket fsock;
  280. enum ripcmd cmd;
  281. register struct rip_refuse *rfl;
  282. struct rip_route entry;
  283. struct route *rp;
  284. struct rip_list *rl;
  285. int32 ttl;
  286. /* receive the RIP packet */
  287. recv_udp(sock,&fsock,&bp);
  288. /* increment the rcvd cnt */
  289. Rip_stat.rcvd++;
  290. /* check the gateway of this packet against the rip_refuse list and
  291.  * discard it if a match is found
  292.  */
  293. for(rfl=Rip_refuse;rfl != NULL;rfl = rfl->next){
  294. if(fsock.address == rfl->target){
  295. Rip_stat.refusals++;
  296. if(Rip_trace > 1)
  297. printf("RIP refused from %sn",
  298.  inet_ntoa(fsock.address));
  299. free_p(&bp);
  300. return;
  301.  }
  302. }
  303. cmd = PULLCHAR(&bp);
  304. /* Check the version of the frame */
  305. if(PULLCHAR(&bp) != RIPVERSION){
  306. free_p(&bp);
  307. Rip_stat.version++;
  308. return;
  309. }
  310. switch(cmd){
  311. case RIPCMD_RESPONSE:
  312. if(Rip_trace > 1)
  313. printf("RIPCMD_RESPONSE from %s n",inet_ntoa(fsock.address));
  314. Rip_stat.response++;
  315. /* See if this interface is on our broadcast list; if so,
  316.  * use its interval to calculate entry lifetimes. Otherwise,
  317.  * use default
  318.  */
  319. ttl = RIP_TTL;
  320. for(rl=Rip_list; rl != NULL; rl = rl->next){
  321. if(rl->iface == iface){
  322. ttl = rl->interval * 4;
  323. break;
  324. }
  325. }
  326. (void)pull16(&bp); /* remove one word of padding */
  327. while(len_p(bp) >= RIPROUTE){
  328. pullentry(&entry,&bp);
  329. proc_rip(iface,fsock.address,&entry,ttl);
  330. }
  331. /* If we can't reach the sender of this update, or if
  332.  * our existing route is not through the interface we
  333.  * got this update on, add him as a host specific entry
  334.  */
  335. if((rp = rt_blookup(fsock.address,32)) != NULL){
  336. /* Host-specific route already exists, refresh it */
  337. start_timer(&rp->timer);
  338. } else if((rp = rt_lookup(fsock.address)) == NULL
  339.  || rp->iface != iface){
  340. entry.addr_fam = RIP_IPFAM;
  341. entry.target = fsock.address;
  342. entry.metric = 0; /* will get incremented to 1 */
  343. proc_rip(iface,fsock.address,&entry,ttl);
  344. }
  345. if(Rip_merge)
  346. rt_merge(Rip_trace);
  347. rip_trigger();
  348. break;
  349. case RIPCMD_REQUEST:
  350. if(Rip_trace > 1)
  351. printf("RIPCMD_REQUESTn");
  352. Rip_stat.request++;
  353. /* For now, just send the whole table with split horizon
  354.  * enabled when the source port is RIP_PORT, and send
  355.  * the whole table with split horizon disable when another
  356.  * source port is used. This should be replaced with a more
  357.  * complete implementation that checks for non-global requests
  358.  */
  359. if(fsock.port == RIP_PORT)
  360. send_routes(fsock.address,fsock.port,1,0,1);
  361. else
  362. send_routes(fsock.address,fsock.port,0,0,1);
  363. break;
  364. default:
  365. if(Rip_trace > 1)
  366. printf("RIPCMD: Unknown Typen");
  367. Rip_stat.unknown++;
  368. break;
  369. } /* switch */
  370. free_p(&bp);
  371. }
  372. /* Apply a set of heuristics for determining the number of significant bits
  373.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  374.  * include the address mask for each entry.
  375.  */
  376. int
  377. nbits(target)
  378. int32 target;
  379. {
  380. int bits;
  381. if(target == 0)
  382. return 0; /* Special case: 0.0.0.0 is the default route */
  383. /* Check the host-part bytes of
  384.  * the address to check for byte-wide zeros
  385.  * which we'll consider to be subnet routes.
  386.  * e.g. 44.80.0.0 will be considered to be equal to 44.80/16
  387.  * whereas 44.80.1.0 will be considered to be 44.80.1/24
  388.  */
  389. switch (hibyte(hiword(target)) >> 6) {
  390. case 3: /* Class C address */
  391. /*is it a host address ? i.e. are there any 1's in the
  392.  * host part ?
  393.  */
  394. if(target & 0xff)
  395. bits = 32;
  396. else
  397. bits = 24;
  398. break;
  399. case 2:  /* Class B address */
  400. if(target & 0xff)
  401. bits = 32;
  402. else if(target & 0xff00)
  403. bits = 24;
  404. else
  405. bits = 16;
  406. break;
  407.         case 0:   /* Class A address */
  408.         case 1:
  409. if(target & 0xff)
  410. bits = 32;
  411. else if(target & 0xff00)
  412. bits = 24;
  413. else if(target & 0xff0000)
  414. bits = 16;
  415. else
  416. bits = 8;
  417. }
  418. return bits;
  419. }
  420. /* Remove and process a RIP response entry from a packet */
  421. static void
  422. proc_rip(iface,gateway,ep,ttl)
  423. struct iface *iface;
  424. int32 gateway;
  425. register struct rip_route *ep;
  426. int32 ttl;
  427. {
  428. unsigned int bits;
  429. register struct route *rp;
  430. int add = 0; /* action flags */
  431. int drop = 0;
  432. int trigger = 0;
  433. if(ep->addr_fam != RIP_IPFAM) {
  434. /* Skip non-IP addresses */
  435. if(Rip_trace > 1)
  436. printf("RIP_rx: Not an IP RIP packet !n");
  437. Rip_stat.addr_family++;
  438. return;
  439. }
  440. /* Guess at the mask, since it's not explicit */
  441. bits = nbits(ep->target);
  442. /* Don't ever add a route to myself through somebody! */
  443. if(bits == 32 && ismyaddr(ep->target) != NULL){
  444. if(Rip_trace > 1){
  445. printf("route to self: %s %ldn",
  446.  inet_ntoa(ep->target),ep->metric);
  447. }
  448. return;
  449. }
  450. /* Find existing entry, if any */
  451. rp = rt_blookup(ep->target,bits);
  452. /* Don't touch private routes */
  453. if(rp != NULL && rp->flags.rtprivate)
  454. return;
  455. if(rp == NULL){
  456. if(ep->metric < RIP_INFINITY){
  457. /* New route; add it and trigger an update */
  458. add++;
  459. trigger++;
  460. }
  461. } else if(rp->metric == RIP_INFINITY){
  462. /* Route is in hold-down; ignore this guy */
  463. if(Rip_trace > 0){
  464. printf("ignored (hold-down): %s %lun",
  465.  inet_ntoa(ep->target),ep->metric);
  466. }
  467. } else if(rp->gateway == gateway && rp->iface == iface){
  468. /* This is the gateway for the entry we already have;
  469.  * restart the timer
  470.  */
  471. set_timer(&rp->timer,ttl*1000L);
  472. start_timer(&rp->timer);
  473. if(rp->metric != ep->metric){
  474. /* Metric has changed. Update it and trigger an
  475.  * update. If route has become unavailable, start
  476.  * the hold-down timeout.
  477.  */
  478. if(Rip_trace){
  479. printf("metric change: %s %lu -> %lun",
  480.  inet_ntoa(ep->target),rp->metric,ep->metric);
  481. }
  482. if(ep->metric == RIP_INFINITY)
  483. rt_timeout(rp); /* Enter hold-down timeout */
  484. else
  485. rp->metric = ep->metric;
  486. trigger++;
  487. }
  488. } else {
  489. /* Entry is from a different gateway than the current route */
  490. if(ep->metric < rp->metric){
  491. /* Switch to a new gateway */
  492. if(Rip_trace > 0){
  493. printf("metric better: %s %lun",
  494.  inet_ntoa(ep->target),ep->metric);
  495. }
  496. drop++;
  497. add++;
  498. trigger++;
  499. } else {
  500. /* Metric is no better, stay with current route */
  501. if(Rip_trace > 1){
  502. printf("metric not better: %s %lun",
  503.  inet_ntoa(ep->target),ep->metric);
  504. }
  505. }
  506. }
  507. if(drop){
  508. /* Switching to a better gateway; delete old entry */
  509. if(Rip_trace){
  510. printf("route drop [%s]/%u",
  511.  inet_ntoa(ep->target),bits);
  512. if(rp != NULL)
  513. printf(" %s %s %lu",rp->iface->name,
  514.  inet_ntoa(rp->gateway),rp->metric);
  515. printf("n");
  516. }
  517. rt_drop(ep->target,bits);
  518. }
  519. if(add){
  520. /* Add a new entry */
  521. if(Rip_trace > 0){
  522. printf("route add [%s]/%u %s",inet_ntoa(ep->target),
  523.  bits,iface->name);
  524. printf(" [%s] %un",inet_ntoa(gateway),
  525.  (int)ep->metric);
  526. }
  527. rp = rt_add(ep->target,(unsigned) bits,gateway,iface,
  528.  (int) ep->metric,ttl,0);
  529. }
  530. /* If the route changed, mark it for a triggered update */
  531. if(trigger){
  532. rp->flags.rttrig = 1;
  533. }
  534. }
  535. /* Send a RIP request packet to the specified destination */
  536. int
  537. ripreq(dest,replyport)
  538. int32 dest;
  539. uint16 replyport;
  540. {
  541. struct mbuf *bp;
  542. struct socket lsock,fsock;
  543. uint8 *cp;
  544. lsock.address = INADDR_ANY;
  545. lsock.port = replyport;
  546. /* if we were given a valid dest addr, ask it (the routers on that net)
  547.  * for a default gateway
  548.  */
  549. if(dest == 0)
  550. return 0;
  551. fsock.address = dest;
  552. fsock.port = RIP_PORT;
  553. /* Send out one RIP Request packet as a broadcast to 'dest'  */
  554. if((bp = alloc_mbuf(RIPHEADER + RIPROUTE)) == NULL)
  555. return -1;
  556. cp = putheader(bp->data,RIPCMD_REQUEST,RIPVERSION);
  557. cp = putentry(cp,0,0L,RIP_INFINITY);
  558. bp->cnt = RIPHEADER + RIPROUTE;
  559. send_udp(&lsock, &fsock,0,0,&bp,bp->cnt,0,0);
  560. Rip_stat.output++;
  561. return 0;
  562. }
  563. void
  564. pullentry(ep,bpp)
  565. register struct rip_route *ep;
  566. struct mbuf **bpp;
  567. {
  568. ep->addr_fam = pull16(bpp);
  569. (void)pull16(bpp);
  570. ep->target = pull32(bpp);
  571. (void)pull32(bpp);
  572. (void)pull32(bpp);
  573. ep->metric = pull32(bpp);
  574. }
  575. /* Write the header of a RIP packet */
  576. static uint8 *
  577. putheader(cp,command,version)
  578. register uint8 *cp;
  579. enum ripcmd command;
  580. uint8 version;
  581. {
  582. *cp++ = command;
  583. *cp++ = version;
  584. return put16(cp,0);
  585. }
  586. /* Write a single entry into a rip packet */
  587. static uint8 *
  588. putentry(cp,fam,target,metric)
  589. register uint8 *cp;
  590. uint16 fam;
  591. int32 target;
  592. int32 metric;
  593. {
  594. cp = put16(cp,fam);
  595. cp = put16(cp,0);
  596. cp = put32(cp,target);
  597. cp = put32(cp,0L);
  598. cp = put32(cp,0L);
  599. return put32(cp,metric);
  600. }
  601. /* Route timeout handler. If route has already been marked for deletion
  602.  * then delete it. Otherwise mark for deletion and restart timer.
  603.  */
  604. void
  605. rt_timeout(s)
  606. void *s;
  607. {
  608. register struct route *rp = (struct route *)s;
  609. stop_timer(&rp->timer);
  610. if(rp->metric < RIP_INFINITY){
  611. rp->metric = RIP_INFINITY;
  612. if(dur_timer(&rp->timer) == 0)
  613. set_timer(&rp->timer,RIP_TTL*1000L);
  614. /* wait 2/3 of timeout before garbage collect */
  615. set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  616. rp->timer.func = (void *)rt_timeout;
  617. rp->timer.arg = (void *)rp;
  618. start_timer(&rp->timer);
  619. /* Route changed; mark it for triggered update */
  620. rp->flags.rttrig = 1;
  621. rip_trigger();
  622. } else {
  623. rt_drop(rp->target,rp->bits);
  624. }
  625. }