00001
00002
00003
00004
00005
00006
00007
00008 #define nil 0
00009 #include <sys/types.h>
00010 #include <errno.h>
00011 #include <fcntl.h>
00012 #include <stddef.h>
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <time.h>
00017 #include <limits.h>
00018 #include <unistd.h>
00019 #include <signal.h>
00020 #include <sys/ioctl.h>
00021 #include <sys/asynchio.h>
00022 #include <net/hton.h>
00023 #include <net/netlib.h>
00024 #include <net/gen/in.h>
00025 #include <net/gen/ip_hdr.h>
00026 #include <net/gen/icmp.h>
00027 #include <net/gen/icmp_hdr.h>
00028 #include <net/gen/ip_io.h>
00029 #include <net/gen/inet.h>
00030 #include <net/gen/netdb.h>
00031 #include <net/gen/oneCsum.h>
00032 #include <net/gen/socket.h>
00033 #include <net/gen/udp.h>
00034 #include <net/gen/udp_hdr.h>
00035 #include <net/gen/udp_io.h>
00036
00037 #define MAX_SOLICITATIONS 3
00038 #define SOLICITATION_INTERVAL 3
00039 #define DEST_TO (10*60)
00040 #define NEW_ROUTE (5*60)
00041 #define DANGER (2*60)
00042 #define DEAD_TO (24L*60*60)
00043 #define DEAD_PREF 0x80000000L
00044 #define MaxAdvertisementInterval (DEST_TO/2)
00045 #define AdvertisementLifetime DEST_TO
00046 #define PRIO_OFF_DEF -1024
00047 #define RIP_REPLY 2
00048
00049
00050 #define IMMEDIATELY ((time_t) ((time_t) -1 < 0 ? LONG_MIN : 0))
00051 #define NEVER ((time_t) ((time_t) -1 < 0 ? LONG_MAX : ULONG_MAX))
00052
00053 #if !__minix_vmd
00054
00055 int do_rdisc= 1;
00056 int do_rip= 0;
00057 #else
00058
00059 #define do_rdisc 1
00060 #define do_rip 1
00061 #endif
00062
00063 int rip_fd;
00064 int irdp_fd;
00065
00066 char *udp_device;
00067 char *ip_device;
00068
00069 int priority_offset;
00070
00071 int bcast= 0;
00072 int debug= 0;
00073
00074 char rip_buf[8192];
00075 char irdp_buf[1024];
00076
00077 typedef struct routeinfo
00078 {
00079 u8_t command;
00080 u8_t version;
00081 u16_t zero1;
00082 struct routedata {
00083 u16_t family;
00084 u16_t zero2;
00085 u32_t ip_addr;
00086 u32_t zero3, zero4;
00087 u32_t metric;
00088 } data[1];
00089 } routeinfo_t;
00090
00091 typedef struct table
00092 {
00093 ipaddr_t tab_gw;
00094 i32_t tab_pref;
00095 time_t tab_time;
00096 } table_t;
00097
00098 table_t *table;
00099 size_t table_size;
00100
00101 int sol_retries= MAX_SOLICITATIONS;
00102 time_t next_sol= IMMEDIATELY;
00103 time_t next_advert= NEVER;
00104 time_t router_advert_valid= IMMEDIATELY;
00105 time_t now;
00106
00107 void report(const char *label)
00108
00109 {
00110 fprintf(stderr, "irdpd: %s: %s\n", label, strerror(errno));
00111 }
00112
00113 void fatal(const char *label)
00114
00115 {
00116 report(label);
00117 exit(1);
00118 }
00119
00120 #if DEBUG
00121 char *addr2name(ipaddr_t host)
00122
00123 {
00124 struct hostent *hostent;
00125
00126 hostent= gethostbyaddr((char *) &host, sizeof(host), AF_INET);
00127 return hostent == nil ? inet_ntoa(host) : hostent->h_name;
00128 }
00129 #else
00130 #define addr2name(host) inet_ntoa(host)
00131 #endif
00132
00133 void print_table(void)
00134
00135 {
00136 int i;
00137 table_t *ptab;
00138 struct tm *tm;
00139
00140 for (i= 0, ptab= table; i < table_size; i++, ptab++) {
00141 if (ptab->tab_time < now - DEAD_TO) continue;
00142
00143 tm= localtime(&ptab->tab_time);
00144 printf("%-40s %6ld %02d:%02d:%02d\n",
00145 addr2name(ptab->tab_gw),
00146 (long) ptab->tab_pref,
00147 tm->tm_hour, tm->tm_min, tm->tm_sec);
00148 }
00149 }
00150
00151 void advertize(ipaddr_t host)
00152
00153 {
00154 char *buf, *data;
00155 ip_hdr_t *ip_hdr;
00156 icmp_hdr_t *icmp_hdr;
00157 int i;
00158 table_t *ptab;
00159
00160 buf= malloc(sizeof(*ip_hdr) + offsetof(icmp_hdr_t, ih_dun.uhd_data)
00161 + table_size * (sizeof(ipaddr_t) + sizeof(u32_t)));
00162 if (buf == nil) fatal("heap error");
00163
00164 ip_hdr= (ip_hdr_t *) buf;
00165 icmp_hdr= (icmp_hdr_t *) (ip_hdr + 1);
00166
00167 ip_hdr->ih_vers_ihl= 0x45;
00168 ip_hdr->ih_dst= host;
00169
00170 icmp_hdr->ih_type= ICMP_TYPE_ROUTER_ADVER;
00171 icmp_hdr->ih_code= 0;
00172 icmp_hdr->ih_hun.ihh_ram.iram_na= 0;
00173 icmp_hdr->ih_hun.ihh_ram.iram_aes= 2;
00174 icmp_hdr->ih_hun.ihh_ram.iram_lt= htons(AdvertisementLifetime);
00175 data= (char *) icmp_hdr->ih_dun.uhd_data;
00176
00177
00178 for (i= 0, ptab= table; i < table_size; i++, ptab++) {
00179 if (ptab->tab_time < now - DEAD_TO) continue;
00180
00181 icmp_hdr->ih_hun.ihh_ram.iram_na++;
00182 if (ptab->tab_time < now - DEST_TO) ptab->tab_pref= DEAD_PREF;
00183 * (ipaddr_t *) data= ptab->tab_gw;
00184 data+= sizeof(ipaddr_t);
00185 * (i32_t *) data= htonl(ptab->tab_pref);
00186 data+= sizeof(i32_t);
00187 }
00188 icmp_hdr->ih_chksum= 0;
00189 icmp_hdr->ih_chksum= ~oneC_sum(0, icmp_hdr, data - (char *) icmp_hdr);
00190
00191 if (icmp_hdr->ih_hun.ihh_ram.iram_na > 0) {
00192
00193
00194 if (debug) {
00195 printf("Routing table send to %s:\n", addr2name(host));
00196 print_table();
00197 }
00198
00199 if (write(irdp_fd, buf, data - buf) < 0) {
00200 (errno == EIO ? fatal : report)(ip_device);
00201 }
00202 }
00203 free(buf);
00204 }
00205
00206 void time_functions(void)
00207
00208 {
00209 if (now >= next_sol) {
00210 char buf[sizeof(ip_hdr_t) + 8];
00211 ip_hdr_t *ip_hdr;
00212 icmp_hdr_t *icmp_hdr;
00213
00214 if (sol_retries == 0) {
00215
00216 next_sol= NEVER;
00217 #if !__minix_vmd
00218
00219 if (table_size == 0) {
00220 do_rip= 1;
00221 do_rdisc= 0;
00222 }
00223 #endif
00224 return;
00225 }
00226
00227
00228 ip_hdr= (ip_hdr_t *) buf;
00229 icmp_hdr= (icmp_hdr_t *) (ip_hdr + 1);
00230
00231 ip_hdr->ih_vers_ihl= 0x45;
00232 ip_hdr->ih_dst= HTONL(0xFFFFFFFFL);
00233
00234 icmp_hdr->ih_type= ICMP_TYPE_ROUTE_SOL;
00235 icmp_hdr->ih_code= 0;
00236 icmp_hdr->ih_chksum= 0;
00237 icmp_hdr->ih_hun.ihh_unused= 0;
00238 icmp_hdr->ih_chksum= ~oneC_sum(0, icmp_hdr, 8);
00239
00240 if (debug) printf("Broadcasting router solicitation\n");
00241
00242 if (write(irdp_fd, buf, sizeof(buf)) < 0)
00243 fatal("sending router solicitation failed");
00244
00245
00246 next_sol= now + SOLICITATION_INTERVAL;
00247
00248 sol_retries--;
00249 }
00250
00251 if (now >= next_advert) {
00252
00253
00254
00255
00256 advertize(bcast ? HTONL(0xFFFFFFFFL) : HTONL(0x7F000001L));
00257 next_advert= now + MaxAdvertisementInterval;
00258 #if !__minix_vmd
00259
00260 do_rip= 1;
00261 do_rdisc= 0;
00262 #endif
00263 }
00264 }
00265
00266 void add_gateway(ipaddr_t host, i32_t pref)
00267
00268 {
00269 table_t *oldest, *ptab;
00270 int i;
00271
00272
00273 oldest= nil;
00274 for (i= 0, ptab= table; i < table_size; i++, ptab++) {
00275 if (ptab->tab_gw == host) break;
00276
00277 if (oldest == nil || ptab->tab_time < oldest->tab_time)
00278 oldest= ptab;
00279 }
00280
00281
00282 if (oldest != nil && oldest->tab_time >= now - DEST_TO) oldest= nil;
00283
00284
00285 if (i == table_size && oldest == nil) {
00286 table_size++;
00287 table= realloc(table, table_size * sizeof(*table));
00288 if (table == nil) fatal("heap error");
00289 oldest= &table[table_size - 1];
00290 }
00291
00292 if (oldest != nil) {
00293 ptab= oldest;
00294 ptab->tab_gw= host;
00295 ptab->tab_pref= DEAD_PREF;
00296 }
00297
00298
00299 if (pref >= ptab->tab_pref || ptab->tab_time <= now - NEW_ROUTE) {
00300 ptab->tab_pref= pref;
00301 ptab->tab_time= now;
00302 }
00303 }
00304
00305 void rip_incoming(ssize_t n)
00306
00307
00308
00309 {
00310 udp_io_hdr_t *udp_io_hdr;
00311 u32_t default_dist;
00312 i32_t pref;
00313 routeinfo_t *routeinfo;
00314 struct routedata *data, *end;
00315
00316
00317 if (now + MaxAdvertisementInterval < router_advert_valid) return;
00318
00319 udp_io_hdr= (udp_io_hdr_t *) rip_buf;
00320 if (udp_io_hdr->uih_data_len != n - sizeof(*udp_io_hdr)) {
00321 if (debug) printf("Bad sized route packet (discarded)\n");
00322 return;
00323 }
00324 routeinfo= (routeinfo_t *) (rip_buf + sizeof(*udp_io_hdr)
00325 + udp_io_hdr->uih_ip_opt_len);
00326
00327 if (routeinfo->command != RIP_REPLY) {
00328 if (debug) {
00329 printf("RIP-%d packet command %d ignored\n",
00330 routeinfo->version, routeinfo->command);
00331 }
00332 return;
00333 }
00334
00335
00336 end= (struct routedata *) (rip_buf + n);
00337 default_dist= (u32_t) -1;
00338 for (data= routeinfo->data; data < end; data++) {
00339 if (ntohs(data->family) != AF_INET || data->ip_addr != 0)
00340 continue;
00341 default_dist= ntohl(data->metric);
00342 if (default_dist >= 256) {
00343 if (debug) {
00344 printf("Strange metric %lu\n",
00345 (unsigned long) default_dist);
00346 }
00347 }
00348 }
00349 pref= default_dist >= 256 ? 1 : 512 - default_dist;
00350 pref+= priority_offset;
00351
00352
00353 add_gateway(udp_io_hdr->uih_src_addr, pref);
00354
00355 if (debug) {
00356 printf("Routing table after RIP-%d packet from %s:\n",
00357 routeinfo->version,
00358 addr2name(udp_io_hdr->uih_src_addr));
00359 print_table();
00360 }
00361
00362
00363 if (next_advert == NEVER) next_advert= IMMEDIATELY;
00364 }
00365
00366 void irdp_incoming(ssize_t n)
00367
00368
00369
00370
00371 {
00372 ip_hdr_t *ip_hdr;
00373 icmp_hdr_t *icmp_hdr;
00374 int ip_hdr_len;
00375 char *data;
00376 int i;
00377 int router;
00378 ipaddr_t addr;
00379 i32_t pref;
00380 time_t valid;
00381
00382 ip_hdr= (ip_hdr_t *) irdp_buf;
00383 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
00384 if (n < ip_hdr_len + 8) {
00385 if (debug) printf("Bad sized ICMP (discarded)\n");
00386 return;
00387 }
00388
00389 icmp_hdr= (icmp_hdr_t *)(irdp_buf + ip_hdr_len);
00390
00391
00392 if (ip_hdr->ih_src == ip_hdr->ih_dst) return;
00393 if ((htonl(ip_hdr->ih_src) & 0xFF000000L) == 0x7F000000L) return;
00394
00395 if (icmp_hdr->ih_type != ICMP_TYPE_ROUTER_ADVER) return;
00396
00397
00398
00399
00400 sol_retries= 0;
00401
00402
00403
00404
00405
00406 router= 0;
00407 data= (char *) icmp_hdr->ih_dun.uhd_data;
00408 for (i= 0; i < icmp_hdr->ih_hun.ihh_ram.iram_na; i++) {
00409 addr= * (ipaddr_t *) data;
00410 data+= sizeof(ipaddr_t);
00411 pref= htonl(* (i32_t *) data);
00412 data+= sizeof(i32_t);
00413
00414 if (addr == ip_hdr->ih_src) {
00415
00416 router= 1;
00417 }
00418 add_gateway(addr, pref);
00419 }
00420
00421 valid= now + ntohs(icmp_hdr->ih_hun.ihh_ram.iram_lt);
00422 if (router) router_advert_valid= valid;
00423
00424
00425
00426
00427 if (router || next_advert > valid - DANGER)
00428 next_advert= valid - DANGER;
00429
00430 if (debug) {
00431 printf("Routing table after advert received from %s:\n",
00432 addr2name(ip_hdr->ih_src));
00433 print_table();
00434 if (router) {
00435 struct tm *tm= localtime(&router_advert_valid);
00436 printf(
00437 "This router advert is valid until %02d:%02d:%02d\n",
00438 tm->tm_hour, tm->tm_min, tm->tm_sec);
00439 }
00440 }
00441 }
00442
00443 void sig_handler(int sig)
00444
00445 {
00446 switch (sig) {
00447 case SIGUSR1: debug++; break;
00448 case SIGUSR2: debug= 0; break;
00449 }
00450 }
00451
00452 void usage(void)
00453 {
00454 fprintf(stderr,
00455 "Usage: irdpd [-bd] [-U udp-device] [-I ip-device] [-o priority-offset]\n");
00456 exit(1);
00457 }
00458
00459 int main(int argc, char **argv)
00460 {
00461 int i;
00462 struct servent *service;
00463 udpport_t route_port;
00464 nwio_udpopt_t udpopt;
00465 nwio_ipopt_t ipopt;
00466 asynchio_t asyn;
00467 time_t timeout;
00468 struct timeval tv;
00469 struct sigaction sa;
00470 char *offset_arg, *offset_end;
00471 long arg;
00472
00473 udp_device= ip_device= nil;
00474 offset_arg= nil;
00475
00476 for (i = 1; i < argc && argv[i][0] == '-'; i++) {
00477 char *p= argv[i] + 1;
00478
00479 if (p[0] == '-' && p[1] == 0) { i++; break; }
00480
00481 while (*p != 0) {
00482 switch (*p++) {
00483 case 'U':
00484 if (udp_device != nil) usage();
00485 if (*p == 0) {
00486 if (++i == argc) usage();
00487 p= argv[i];
00488 }
00489 udp_device= p;
00490 p= "";
00491 break;
00492 case 'I':
00493 if (ip_device != nil) usage();
00494 if (*p == 0) {
00495 if (++i == argc) usage();
00496 p= argv[i];
00497 }
00498 ip_device= p;
00499 p= "";
00500 break;
00501 case 'o':
00502 if (offset_arg != nil) usage();
00503 if (*p == 0) {
00504 if (++i == argc) usage();
00505 p= argv[i];
00506 }
00507 offset_arg= p;
00508 p= "";
00509 break;
00510 case 'b':
00511 bcast= 1;
00512 break;
00513 case 's':
00514
00515 break;
00516 case 'd':
00517 debug= 1;
00518 break;
00519 default:
00520 usage();
00521 }
00522 }
00523 }
00524 if (i != argc) usage();
00525
00526
00527 sa.sa_handler= sig_handler;
00528 sigemptyset(&sa.sa_mask);
00529 sa.sa_flags= 0;
00530 sigaction(SIGUSR1, &sa, nil);
00531 sigaction(SIGUSR2, &sa, nil);
00532
00533 if (udp_device == nil && (udp_device= getenv("UDP_DEVICE")) == nil)
00534 udp_device= UDP_DEVICE;
00535
00536 if (ip_device == nil && (ip_device= getenv("IP_DEVICE")) == nil)
00537 ip_device= IP_DEVICE;
00538
00539 if (offset_arg == nil) {
00540 priority_offset= PRIO_OFF_DEF;
00541 } else {
00542 arg= strtol(offset_arg, &offset_end, 0);
00543 if (*offset_end != 0 || (priority_offset= arg) != arg) usage();
00544 }
00545
00546 if ((service= getservbyname("route", "udp")) == nil) {
00547 fprintf(stderr,
00548 "irdpd: unable to look up the port number for the 'route' service\n");
00549 exit(1);
00550 }
00551
00552 route_port= (udpport_t) service->s_port;
00553
00554 if ((rip_fd= open(udp_device, O_RDWR)) < 0) fatal(udp_device);
00555
00556 udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SET | NWUO_DI_LOC
00557 | NWUO_EN_BROAD | NWUO_RP_SET | NWUO_RA_ANY | NWUO_RWDATALL
00558 | NWUO_DI_IPOPT;
00559 udpopt.nwuo_locport= route_port;
00560 udpopt.nwuo_remport= route_port;
00561 if (ioctl(rip_fd, NWIOSUDPOPT, &udpopt) < 0)
00562 fatal("setting UDP options failed");
00563
00564 if ((irdp_fd= open(ip_device, O_RDWR)) < 0) fatal(ip_device);
00565
00566 ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD
00567 | NWIO_REMANY | NWIO_PROTOSPEC
00568 | NWIO_HDR_O_SPEC | NWIO_RWDATALL;
00569 ipopt.nwio_tos= 0;
00570 ipopt.nwio_ttl= 1;
00571 ipopt.nwio_df= 0;
00572 ipopt.nwio_hdropt.iho_opt_siz= 0;
00573 ipopt.nwio_rem= HTONL(0xFFFFFFFFL);
00574 ipopt.nwio_proto= IPPROTO_ICMP;
00575
00576 if (ioctl(irdp_fd, NWIOSIPOPT, &ipopt) < 0)
00577 fatal("can't configure ICMP channel");
00578
00579 asyn_init(&asyn);
00580
00581 while (1) {
00582 ssize_t r;
00583
00584 if (do_rip) {
00585
00586 r= asyn_read(&asyn, rip_fd, rip_buf, sizeof(rip_buf));
00587 if (r < 0) {
00588 if (errno == EIO) fatal(udp_device);
00589 if (errno != EINPROGRESS) report(udp_device);
00590 } else {
00591 now= time(nil);
00592 rip_incoming(r);
00593 }
00594 }
00595
00596 if (do_rdisc) {
00597
00598 r= asyn_read(&asyn, irdp_fd, irdp_buf,
00599 sizeof(irdp_buf));
00600 if (r < 0) {
00601 if (errno == EIO) fatal(ip_device);
00602 if (errno != EINPROGRESS) report(ip_device);
00603 } else {
00604 now= time(nil);
00605 irdp_incoming(r);
00606 }
00607 }
00608 fflush(stdout);
00609
00610
00611 timeout= next_sol < next_advert ? next_sol : next_advert;
00612
00613
00614 tv.tv_sec= timeout;
00615 tv.tv_usec= 0;
00616 if (asyn_wait(&asyn, 0, timeout == NEVER ? nil : &tv) < 0) {
00617
00618 if (errno != EINTR && errno != EAGAIN)
00619 fatal("asyn_wait()");
00620 now= time(nil);
00621 time_functions();
00622 }
00623 }
00624 }