#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../pathnames.h" #include "rip98d.h" struct dest_struct dest_list[50]; int dest_count; int debug = FALSE; int route_restrict = FALSE; int logging = FALSE; struct route_struct *first_route; static void terminate(int sig) { if (logging) { syslog(LOG_INFO, "terminating on SIGTERM\n"); closelog(); } exit(0); } unsigned int mask2bits(unsigned int mask) { mask = ~mask; if (!mask) return 32; return __builtin_clz(mask); } unsigned int bits2mask(unsigned int bits) { if (!bits) return 0; return ~0 << (sizeof(unsigned int) * 8 - bits); } static unsigned int hex2int(char *buffer) { return strtoul(buffer, NULL, 16); } static int read_routes(void) { struct route_struct *route, *temp; char buffer[1023], iface[16], net_addr[64], gate_addr[64], mask_addr[64]; int n, refcnt, use, metric, mss, window; unsigned int iflags; struct in_addr address; unsigned long int netmask; unsigned long int network; FILE *fp; if (first_route != NULL) { route = first_route; while (route != NULL) { temp = route->next; free(route); route = temp; } first_route = NULL; } fp = fopen(PROC_IP_ROUTE_FILE, "r"); if (fp == NULL) { if (logging) syslog(LOG_ERR, "error cannot open %s\n", PROC_IP_ROUTE_FILE); return FALSE; } while (fgets(buffer, 1023, fp) != NULL) { n = sscanf(buffer, "%s %s %s %X %d %d %d %s %d %d\n", iface, net_addr, gate_addr, &iflags, &refcnt, &use, &metric, mask_addr, &mss, &window); if (n != 10) continue; address.s_addr = hex2int(net_addr); netmask = mask2bits(ntohl(hex2int(mask_addr))); network = inet_netof(address); if (network == 0 || network == 127) { if (debug && logging) syslog(LOG_DEBUG, "rejecting route to %s/%ld - should not be propogated\n", inet_ntoa(address), netmask); continue; } if (route_restrict) { if (inet_netof(address) != 44) { if (debug && logging) syslog(LOG_DEBUG, "rejecting route to %s/%ld - not ampr.org\n", inet_ntoa(address), netmask); continue; } } route = malloc(sizeof(struct route_struct)); if (route == NULL) { if (logging) syslog(LOG_ERR, "out of memory !\n"); return FALSE; } route->addr = address; route->bits = netmask; route->metric = metric; route->action = (iflags & RTF_DYNAMIC) ? ORIG_ROUTE : FIXED_ROUTE; route->next = first_route; first_route = route; } fclose(fp); return TRUE; } static int load_dests(void) { struct hostent *host; char buffer[255], *s; FILE *fp; fp = fopen(CONF_RIP98D_FILE, "r"); if (fp == NULL) { fprintf(stderr, "rip98d: cannot open config file\n"); return FALSE; } while (fgets(buffer, 255, fp) != NULL) { s = strchr(buffer, '\n'); if (s != NULL) *s = '\0'; host = gethostbyname(buffer); if (host == NULL) { fprintf(stderr, "rip98d: cannot resolve name %s\n", buffer); fclose(fp); return FALSE; } memcpy(&dest_list[dest_count].dest_addr, host->h_addr, host->h_length); dest_count++; } fclose(fp); if (dest_count == 0) return FALSE; return TRUE; } int main(int argc, char **argv) { int s, i; struct sockaddr_in loc_addr; struct timeval timeout; time_t timenow, timelast = 0; int interval = 3600; fd_set fdset; if (!load_dests()) { fprintf(stderr, "rip98d: no destination routers defined\n"); return 1; } while ((i = getopt(argc, argv, "dlrt:v")) != -1) { switch (i) { case 'd': debug = TRUE; break; case 'l': logging = TRUE; break; case 'r': route_restrict = TRUE; break; case 't': interval = atoi(optarg) * 60; if (interval < 60 || interval > 7200) { fprintf(stderr, "rip98d: invalid time interval\n"); return 1; } break; case 'v': printf("rip98d: %s\n", FULL_VER); return 0; case ':': fprintf(stderr, "rip98d: invalid time interval\n"); return 1; case '?': fprintf(stderr, "usage: rip98d [-d] [-l] [-r] [-t interval] [-v]\n"); return 1; } } signal(SIGTERM, terminate); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("rip98d: socket"); return 1; } memset(&loc_addr, 0, sizeof(loc_addr)); loc_addr.sin_family = AF_INET; loc_addr.sin_addr.s_addr = htonl(INADDR_ANY); loc_addr.sin_port = htons(RIP_PORT); if (bind(s, &loc_addr, sizeof(loc_addr)) < 0) { perror("rip98d: bind"); close(s); return 1; } if (!daemon_start(FALSE)) { fprintf(stderr, "rip98d: cannot become a daemon\n"); close(s); return 1; } if (logging) { openlog("rip98d", LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "starting"); } for (;;) { FD_ZERO(&fdset); FD_SET(s, &fdset); timeout.tv_sec = 60; timeout.tv_usec = 0; select(s + 1, &fdset, NULL, NULL, &timeout); if (!read_routes()) { if (logging) closelog(); return 1; } if (FD_ISSET(s, &fdset)) receive_routes(s); time(&timenow); if ((timenow - timelast) > interval) { timelast = timenow; if (first_route != NULL) transmit_routes(s); } } }