PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

commands/irdpd/irdpd.c

http://www.minix3.org/
C | 635 lines | 484 code | 89 blank | 62 comment | 145 complexity | 658638b5fb12e25a6d33f0dfa0b68cd9 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* irdpd 1.10 - Internet router discovery protocol daemon.
  2. * Author: Kees J. Bot
  3. * 28 May 1994
  4. * Activily solicitate or passively look for routers.
  5. * Based heavily on its forerunners, the irdp_sol and rip2icmp daemons by
  6. * Philip Homburg.
  7. */
  8. #define nil 0
  9. #include <sys/types.h>
  10. #include <errno.h>
  11. #include <fcntl.h>
  12. #include <stddef.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include <limits.h>
  18. #include <unistd.h>
  19. #include <signal.h>
  20. #include <sys/ioctl.h>
  21. #include <sys/asynchio.h>
  22. #include <net/hton.h>
  23. #include <net/netlib.h>
  24. #include <net/gen/in.h>
  25. #include <net/gen/ip_hdr.h>
  26. #include <net/gen/icmp.h>
  27. #include <net/gen/icmp_hdr.h>
  28. #include <net/gen/ip_io.h>
  29. #include <net/gen/inet.h>
  30. #include <net/gen/netdb.h>
  31. #include <net/gen/oneCsum.h>
  32. #include <net/gen/socket.h>
  33. #include <net/gen/udp.h>
  34. #include <net/gen/udp_hdr.h>
  35. #include <net/gen/udp_io.h>
  36. #define MAX_SOLICITATIONS 3 /* # router solicitations. */
  37. #define SOLICITATION_INTERVAL 3 /* Secs between solicitate retries. */
  38. #define DEST_TO (10*60) /* 10 minutes */
  39. #define NEW_ROUTE (5*60) /* 5 minutes */
  40. #define DANGER (2*60) /* Nearing a advert timeout? */
  41. #define DEAD_TO (24L*60*60) /* 24 hours */
  42. #define DEAD_PREF 0x80000000L /* From RFC 1256 */
  43. #define MaxAdvertisementInterval (DEST_TO/2) /* Chosen to jive with RIP */
  44. #define AdvertisementLifetime DEST_TO
  45. #define PRIO_OFF_DEF -1024
  46. #define RIP_REPLY 2
  47. /* It's now or never. */
  48. #define IMMEDIATELY ((time_t) ((time_t) -1 < 0 ? LONG_MIN : 0))
  49. #define NEVER ((time_t) ((time_t) -1 < 0 ? LONG_MAX : ULONG_MAX))
  50. #if !__minix_vmd
  51. /* Standard Minix needs to choose between router discovery and RIP info. */
  52. int do_rdisc= 1;
  53. int do_rip= 0;
  54. #else
  55. /* VMD Minix can do both at once. */
  56. #define do_rdisc 1
  57. #define do_rip 1
  58. #endif
  59. int rip_fd; /* For incoming RIP packet. */
  60. int irdp_fd; /* Receive or transmit IRDP packets. */
  61. char *udp_device; /* UDP device to use. */
  62. char *ip_device; /* IP device to use. */
  63. int priority_offset; /* Offset to make my routes less preferred. */
  64. int bcast= 0; /* Broadcast adverts to all. */
  65. int debug= 0;
  66. char rip_buf[8192]; /* Incoming RIP packet buffer. */
  67. char irdp_buf[1024]; /* IRDP buffer. */
  68. typedef struct routeinfo
  69. {
  70. u8_t command;
  71. u8_t version;
  72. u16_t zero1;
  73. struct routedata {
  74. u16_t family;
  75. u16_t zero2;
  76. u32_t ip_addr;
  77. u32_t zero3, zero4;
  78. u32_t metric;
  79. } data[1];
  80. } routeinfo_t;
  81. typedef struct table
  82. {
  83. ipaddr_t tab_gw;
  84. i32_t tab_pref;
  85. time_t tab_time;
  86. } table_t;
  87. table_t *table; /* Collected table of routing info. */
  88. size_t table_size;
  89. int sol_retries= MAX_SOLICITATIONS;
  90. time_t next_sol= IMMEDIATELY;
  91. time_t next_advert= NEVER;
  92. time_t router_advert_valid= IMMEDIATELY;
  93. time_t now;
  94. void report(const char *label)
  95. /* irdpd: /dev/hd0: Device went up in flames */
  96. {
  97. fprintf(stderr, "irdpd: %s: %s\n", label, strerror(errno));
  98. }
  99. void fatal(const char *label)
  100. /* irdpd: /dev/house: Taking this with it */
  101. {
  102. report(label);
  103. exit(1);
  104. }
  105. #if DEBUG
  106. char *addr2name(ipaddr_t host)
  107. /* Translate an IP address to a printable name. */
  108. {
  109. struct hostent *hostent;
  110. hostent= gethostbyaddr((char *) &host, sizeof(host), AF_INET);
  111. return hostent == nil ? inet_ntoa(host) : hostent->h_name;
  112. }
  113. #else
  114. #define addr2name(host) inet_ntoa(host)
  115. #endif
  116. void print_table(void)
  117. /* Show the collected routing table. */
  118. {
  119. int i;
  120. table_t *ptab;
  121. struct tm *tm;
  122. for (i= 0, ptab= table; i < table_size; i++, ptab++) {
  123. if (ptab->tab_time < now - DEAD_TO) continue;
  124. tm= localtime(&ptab->tab_time);
  125. printf("%-40s %6ld %02d:%02d:%02d\n",
  126. addr2name(ptab->tab_gw),
  127. (long) ptab->tab_pref,
  128. tm->tm_hour, tm->tm_min, tm->tm_sec);
  129. }
  130. }
  131. void advertize(ipaddr_t host)
  132. /* Send a router advert to a host. */
  133. {
  134. char *buf, *data;
  135. ip_hdr_t *ip_hdr;
  136. icmp_hdr_t *icmp_hdr;
  137. int i;
  138. table_t *ptab;
  139. buf= malloc(sizeof(*ip_hdr) + offsetof(icmp_hdr_t, ih_dun.uhd_data)
  140. + table_size * (sizeof(ipaddr_t) + sizeof(u32_t)));
  141. if (buf == nil) fatal("heap error");
  142. ip_hdr= (ip_hdr_t *) buf;
  143. icmp_hdr= (icmp_hdr_t *) (ip_hdr + 1);
  144. ip_hdr->ih_vers_ihl= 0x45;
  145. ip_hdr->ih_dst= host;
  146. icmp_hdr->ih_type= ICMP_TYPE_ROUTER_ADVER;
  147. icmp_hdr->ih_code= 0;
  148. icmp_hdr->ih_hun.ihh_ram.iram_na= 0;
  149. icmp_hdr->ih_hun.ihh_ram.iram_aes= 2;
  150. icmp_hdr->ih_hun.ihh_ram.iram_lt= htons(AdvertisementLifetime);
  151. data= (char *) icmp_hdr->ih_dun.uhd_data;
  152. /* Collect gateway entries from the table. */
  153. for (i= 0, ptab= table; i < table_size; i++, ptab++) {
  154. if (ptab->tab_time < now - DEAD_TO) continue;
  155. icmp_hdr->ih_hun.ihh_ram.iram_na++;
  156. if (ptab->tab_time < now - DEST_TO) ptab->tab_pref= DEAD_PREF;
  157. * (ipaddr_t *) data= ptab->tab_gw;
  158. data+= sizeof(ipaddr_t);
  159. * (i32_t *) data= htonl(ptab->tab_pref);
  160. data+= sizeof(i32_t);
  161. }
  162. icmp_hdr->ih_chksum= 0;
  163. icmp_hdr->ih_chksum= ~oneC_sum(0, icmp_hdr, data - (char *) icmp_hdr);
  164. if (icmp_hdr->ih_hun.ihh_ram.iram_na > 0) {
  165. /* Send routing info. */
  166. if (debug) {
  167. printf("Routing table send to %s:\n", addr2name(host));
  168. print_table();
  169. }
  170. if (write(irdp_fd, buf, data - buf) < 0) {
  171. (errno == EIO ? fatal : report)(ip_device);
  172. }
  173. }
  174. free(buf);
  175. }
  176. void time_functions(void)
  177. /* Perform time dependend functions: router solicitation, router advert. */
  178. {
  179. if (now >= next_sol) {
  180. char buf[sizeof(ip_hdr_t) + 8];
  181. ip_hdr_t *ip_hdr;
  182. icmp_hdr_t *icmp_hdr;
  183. if (sol_retries == 0) {
  184. /* Stop soliciting. */
  185. next_sol= NEVER;
  186. #if !__minix_vmd
  187. /* Switch to RIP if no router responded. */
  188. if (table_size == 0) {
  189. do_rip= 1;
  190. do_rdisc= 0;
  191. }
  192. #endif
  193. return;
  194. }
  195. /* Broadcast a router solicitation to find a router. */
  196. ip_hdr= (ip_hdr_t *) buf;
  197. icmp_hdr= (icmp_hdr_t *) (ip_hdr + 1);
  198. ip_hdr->ih_vers_ihl= 0x45;
  199. #ifdef __NBSD_LIBC
  200. ip_hdr->ih_dst= htonl(0xFFFFFFFFL);
  201. #else
  202. ip_hdr->ih_dst= HTONL(0xFFFFFFFFL);
  203. #endif
  204. icmp_hdr->ih_type= ICMP_TYPE_ROUTE_SOL;
  205. icmp_hdr->ih_code= 0;
  206. icmp_hdr->ih_chksum= 0;
  207. icmp_hdr->ih_hun.ihh_unused= 0;
  208. icmp_hdr->ih_chksum= ~oneC_sum(0, icmp_hdr, 8);
  209. if (debug) printf("Broadcasting router solicitation\n");
  210. if (write(irdp_fd, buf, sizeof(buf)) < 0)
  211. fatal("sending router solicitation failed");
  212. /* Schedule the next packet. */
  213. next_sol= now + SOLICITATION_INTERVAL;
  214. sol_retries--;
  215. }
  216. if (now >= next_advert) {
  217. /* Advertize routes to the local host (normally), or
  218. * broadcast them (to keep bad hosts up.)
  219. */
  220. #ifdef __NBSD_LIBC
  221. advertize(bcast ? htonl(0xFFFFFFFFL) : htonl(0x7F000001L));
  222. #else
  223. advertize(bcast ? HTONL(0xFFFFFFFFL) : HTONL(0x7F000001L));
  224. #endif
  225. next_advert= now + MaxAdvertisementInterval;
  226. #if !__minix_vmd
  227. /* Make sure we are listening to RIP now. */
  228. do_rip= 1;
  229. do_rdisc= 0;
  230. #endif
  231. }
  232. }
  233. void add_gateway(ipaddr_t host, i32_t pref)
  234. /* Add a router with given address and preference to the routing table. */
  235. {
  236. table_t *oldest, *ptab;
  237. int i;
  238. /* Look for the host, or select the oldest entry. */
  239. oldest= nil;
  240. for (i= 0, ptab= table; i < table_size; i++, ptab++) {
  241. if (ptab->tab_gw == host) break;
  242. if (oldest == nil || ptab->tab_time < oldest->tab_time)
  243. oldest= ptab;
  244. }
  245. /* Don't evict the oldest if it is still valid. */
  246. if (oldest != nil && oldest->tab_time >= now - DEST_TO) oldest= nil;
  247. /* Expand the table? */
  248. if (i == table_size && oldest == nil) {
  249. table_size++;
  250. table= realloc(table, table_size * sizeof(*table));
  251. if (table == nil) fatal("heap error");
  252. oldest= &table[table_size - 1];
  253. }
  254. if (oldest != nil) {
  255. ptab= oldest;
  256. ptab->tab_gw= host;
  257. ptab->tab_pref= DEAD_PREF;
  258. }
  259. /* Replace an entry if the new one looks more promising. */
  260. if (pref >= ptab->tab_pref || ptab->tab_time <= now - NEW_ROUTE) {
  261. ptab->tab_pref= pref;
  262. ptab->tab_time= now;
  263. }
  264. }
  265. void rip_incoming(ssize_t n)
  266. /* Use a RIP packet to add to the router table. (RIP packets are really for
  267. * between routers, but often it is the only information around.)
  268. */
  269. {
  270. udp_io_hdr_t *udp_io_hdr;
  271. u32_t default_dist;
  272. i32_t pref;
  273. routeinfo_t *routeinfo;
  274. struct routedata *data, *end;
  275. /* We don't care about RIP packets when there are router adverts. */
  276. if (now + MaxAdvertisementInterval < router_advert_valid) return;
  277. udp_io_hdr= (udp_io_hdr_t *) rip_buf;
  278. if (udp_io_hdr->uih_data_len != n - sizeof(*udp_io_hdr)) {
  279. if (debug) printf("Bad sized route packet (discarded)\n");
  280. return;
  281. }
  282. routeinfo= (routeinfo_t *) (rip_buf + sizeof(*udp_io_hdr)
  283. + udp_io_hdr->uih_ip_opt_len);
  284. if (routeinfo->command != RIP_REPLY) {
  285. if (debug) {
  286. printf("RIP-%d packet command %d ignored\n",
  287. routeinfo->version, routeinfo->command);
  288. }
  289. return;
  290. }
  291. /* Look for a default route, the route to the gateway. */
  292. end= (struct routedata *) (rip_buf + n);
  293. default_dist= (u32_t) -1;
  294. for (data= routeinfo->data; data < end; data++) {
  295. if (ntohs(data->family) != AF_INET || data->ip_addr != 0)
  296. continue;
  297. default_dist= ntohl(data->metric);
  298. if (default_dist >= 256) {
  299. if (debug) {
  300. printf("Strange metric %lu\n",
  301. (unsigned long) default_dist);
  302. }
  303. }
  304. }
  305. pref= default_dist >= 256 ? 1 : 512 - default_dist;
  306. pref+= priority_offset;
  307. /* Add the gateway to the table with the calculated preference. */
  308. add_gateway(udp_io_hdr->uih_src_addr, pref);
  309. if (debug) {
  310. printf("Routing table after RIP-%d packet from %s:\n",
  311. routeinfo->version,
  312. addr2name(udp_io_hdr->uih_src_addr));
  313. print_table();
  314. }
  315. /* Start advertizing. */
  316. if (next_advert == NEVER) next_advert= IMMEDIATELY;
  317. }
  318. void irdp_incoming(ssize_t n)
  319. /* Look for router solicitations and router advertisements. The solicitations
  320. * are probably from other irdpd daemons, we answer them if we do not expect
  321. * a real router to answer. The advertisements cause this daemon to shut up.
  322. */
  323. {
  324. ip_hdr_t *ip_hdr;
  325. icmp_hdr_t *icmp_hdr;
  326. int ip_hdr_len;
  327. char *data;
  328. int i;
  329. int router;
  330. ipaddr_t addr;
  331. i32_t pref;
  332. time_t valid;
  333. ip_hdr= (ip_hdr_t *) irdp_buf;
  334. ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
  335. if (n < ip_hdr_len + 8) {
  336. if (debug) printf("Bad sized ICMP (discarded)\n");
  337. return;
  338. }
  339. icmp_hdr= (icmp_hdr_t *)(irdp_buf + ip_hdr_len);
  340. /* Did I send this myself? */
  341. if (ip_hdr->ih_src == ip_hdr->ih_dst) return;
  342. if ((htonl(ip_hdr->ih_src) & 0xFF000000L) == 0x7F000000L) return;
  343. if (icmp_hdr->ih_type != ICMP_TYPE_ROUTER_ADVER) return;
  344. /* Incoming router advertisement, the kind of packet the TCP/IP task
  345. * is very happy with. No need to solicit further.
  346. */
  347. sol_retries= 0;
  348. /* Add router info to our table. Also see if the packet really came
  349. * from a router. If so then we can go dormant for the lifetime of
  350. * the ICMP.
  351. */
  352. router= 0;
  353. data= (char *) icmp_hdr->ih_dun.uhd_data;
  354. for (i= 0; i < icmp_hdr->ih_hun.ihh_ram.iram_na; i++) {
  355. addr= * (ipaddr_t *) data;
  356. data+= sizeof(ipaddr_t);
  357. pref= htonl(* (i32_t *) data);
  358. data+= sizeof(i32_t);
  359. if (addr == ip_hdr->ih_src) {
  360. /* The sender is in the routing table! */
  361. router= 1;
  362. }
  363. add_gateway(addr, pref);
  364. }
  365. valid= now + ntohs(icmp_hdr->ih_hun.ihh_ram.iram_lt);
  366. if (router) router_advert_valid= valid;
  367. /* Restart advertizing close to the timeout of the advert. (No more
  368. * irdpd adverts if the router stays alive.)
  369. */
  370. if (router || next_advert > valid - DANGER)
  371. next_advert= valid - DANGER;
  372. if (debug) {
  373. printf("Routing table after advert received from %s:\n",
  374. addr2name(ip_hdr->ih_src));
  375. print_table();
  376. if (router) {
  377. struct tm *tm= localtime(&router_advert_valid);
  378. printf(
  379. "This router advert is valid until %02d:%02d:%02d\n",
  380. tm->tm_hour, tm->tm_min, tm->tm_sec);
  381. }
  382. }
  383. }
  384. void sig_handler(int sig)
  385. /* A signal changes the debug level. */
  386. {
  387. switch (sig) {
  388. case SIGUSR1: debug++; break;
  389. case SIGUSR2: debug= 0; break;
  390. }
  391. }
  392. void usage(void)
  393. {
  394. fprintf(stderr,
  395. "Usage: irdpd [-bd] [-U udp-device] [-I ip-device] [-o priority-offset]\n");
  396. exit(1);
  397. }
  398. int main(int argc, char **argv)
  399. {
  400. int i;
  401. struct servent *service;
  402. udpport_t route_port;
  403. nwio_udpopt_t udpopt;
  404. nwio_ipopt_t ipopt;
  405. asynchio_t asyn;
  406. time_t timeout;
  407. struct timeval tv;
  408. struct sigaction sa;
  409. char *offset_arg, *offset_end;
  410. long arg;
  411. udp_device= ip_device= nil;
  412. offset_arg= nil;
  413. for (i = 1; i < argc && argv[i][0] == '-'; i++) {
  414. char *p= argv[i] + 1;
  415. if (p[0] == '-' && p[1] == 0) { i++; break; }
  416. while (*p != 0) {
  417. switch (*p++) {
  418. case 'U':
  419. if (udp_device != nil) usage();
  420. if (*p == 0) {
  421. if (++i == argc) usage();
  422. p= argv[i];
  423. }
  424. udp_device= p;
  425. p= "";
  426. break;
  427. case 'I':
  428. if (ip_device != nil) usage();
  429. if (*p == 0) {
  430. if (++i == argc) usage();
  431. p= argv[i];
  432. }
  433. ip_device= p;
  434. p= "";
  435. break;
  436. case 'o':
  437. if (offset_arg != nil) usage();
  438. if (*p == 0) {
  439. if (++i == argc) usage();
  440. p= argv[i];
  441. }
  442. offset_arg= p;
  443. p= "";
  444. break;
  445. case 'b':
  446. bcast= 1;
  447. break;
  448. case 's':
  449. /*obsolete*/
  450. break;
  451. case 'd':
  452. debug= 1;
  453. break;
  454. default:
  455. usage();
  456. }
  457. }
  458. }
  459. if (i != argc) usage();
  460. /* Debug level signals. */
  461. sa.sa_handler= sig_handler;
  462. sigemptyset(&sa.sa_mask);
  463. sa.sa_flags= 0;
  464. sigaction(SIGUSR1, &sa, nil);
  465. sigaction(SIGUSR2, &sa, nil);
  466. if (udp_device == nil && (udp_device= getenv("UDP_DEVICE")) == nil)
  467. udp_device= UDP_DEVICE;
  468. if (ip_device == nil && (ip_device= getenv("IP_DEVICE")) == nil)
  469. ip_device= IP_DEVICE;
  470. if (offset_arg == nil) {
  471. priority_offset= PRIO_OFF_DEF;
  472. } else {
  473. arg= strtol(offset_arg, &offset_end, 0);
  474. if (*offset_end != 0 || (priority_offset= arg) != arg) usage();
  475. }
  476. if ((service= getservbyname("route", "udp")) == nil) {
  477. fprintf(stderr,
  478. "irdpd: unable to look up the port number for the 'route' service\n");
  479. exit(1);
  480. }
  481. route_port= (udpport_t) service->s_port;
  482. if ((rip_fd= open(udp_device, O_RDWR)) < 0) fatal(udp_device);
  483. udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SET | NWUO_DI_LOC
  484. | NWUO_EN_BROAD | NWUO_RP_SET | NWUO_RA_ANY | NWUO_RWDATALL
  485. | NWUO_DI_IPOPT;
  486. udpopt.nwuo_locport= route_port;
  487. udpopt.nwuo_remport= route_port;
  488. if (ioctl(rip_fd, NWIOSUDPOPT, &udpopt) < 0)
  489. fatal("setting UDP options failed");
  490. if ((irdp_fd= open(ip_device, O_RDWR)) < 0) fatal(ip_device);
  491. ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD
  492. | NWIO_REMANY | NWIO_PROTOSPEC
  493. | NWIO_HDR_O_SPEC | NWIO_RWDATALL;
  494. ipopt.nwio_tos= 0;
  495. ipopt.nwio_ttl= 1;
  496. ipopt.nwio_df= 0;
  497. ipopt.nwio_hdropt.iho_opt_siz= 0;
  498. #ifdef __NBSD_LIBC
  499. ipopt.nwio_rem= htonl(0xFFFFFFFFL);
  500. #else
  501. ipopt.nwio_rem= HTONL(0xFFFFFFFFL);
  502. #endif
  503. ipopt.nwio_proto= IPPROTO_ICMP;
  504. if (ioctl(irdp_fd, NWIOSIPOPT, &ipopt) < 0)
  505. fatal("can't configure ICMP channel");
  506. asyn_init(&asyn);
  507. while (1) {
  508. ssize_t r;
  509. if (do_rip) {
  510. /* Try a RIP read. */
  511. r= asyn_read(&asyn, rip_fd, rip_buf, sizeof(rip_buf));
  512. if (r < 0) {
  513. if (errno == EIO) fatal(udp_device);
  514. if (errno != EINPROGRESS) report(udp_device);
  515. } else {
  516. now= time(nil);
  517. rip_incoming(r);
  518. }
  519. }
  520. if (do_rdisc) {
  521. /* Try an IRDP read. */
  522. r= asyn_read(&asyn, irdp_fd, irdp_buf,
  523. sizeof(irdp_buf));
  524. if (r < 0) {
  525. if (errno == EIO) fatal(ip_device);
  526. if (errno != EINPROGRESS) report(ip_device);
  527. } else {
  528. now= time(nil);
  529. irdp_incoming(r);
  530. }
  531. }
  532. fflush(stdout);
  533. /* Compute the next wakeup call. */
  534. timeout= next_sol < next_advert ? next_sol : next_advert;
  535. /* Wait for a RIP or IRDP packet or a timeout. */
  536. tv.tv_sec= timeout;
  537. tv.tv_usec= 0;
  538. if (asyn_wait(&asyn, 0, timeout == NEVER ? nil : &tv) < 0) {
  539. /* Timeout? */
  540. if (errno != EINTR && errno != EAGAIN)
  541. fatal("asyn_wait()");
  542. now= time(nil);
  543. time_functions();
  544. }
  545. }
  546. }