static int INET_setroute(int action, int options, char **args) { struct rtentry rt; char target[128], gateway[128] = "NONE", netmask[128] = "default"; int xflag, isnet; xflag = 0; if (!strcmp(*args, "#net")) { xflag = 1; args++; } else if (!strcmp(*args, "#host")) { xflag = 2; args++; } if (*args == NULL) return usage(E_OPTERR); safe_strncpy(target, *args++, (sizeof target)); /* Clean out the RTREQ structure. */ memset((char *) &rt, 0, sizeof(struct rtentry)); /* Special hack for /prefix syntax */ { union { struct sockaddr_in m; struct sockaddr d; } mask; int n; n = inet_aftype.getmask(target, &mask.d, netmask); if (n < 0) return usage(E_OPTERR); else if (n) rt.rt_genmask = full_mask(mask.d); } /* Prefer hostname lookup is -host flag was given */ if ((isnet = inet_aftype.input((xflag!=2? 0: 256), target, &rt.rt_dst)) < 0) { inet_aftype.herror(target); return (E_LOOKUP); } switch (xflag) { case 1: isnet = 1; break; case 2: isnet = 0; break; } /* Fill in the other fields. */ rt.rt_flags = (RTF_UP | RTF_HOST); if (isnet) rt.rt_flags &= ~RTF_HOST; while (*args) { if (!strcmp(*args, "metric")) { int metric; args++; if (!*args || !isdigit(**args)) return usage(E_OPTERR); metric = atoi(*args); #if HAVE_NEW_ADDRT rt.rt_metric = metric + 1; #else ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); #endif args++; continue; } if (!strcmp(*args, "netmask")) { struct sockaddr mask; args++; if (!*args || mask_in_addr(rt)) return usage(E_OPTERR); safe_strncpy(netmask, *args, (sizeof netmask)); if ((isnet = inet_aftype.input(0, netmask, &mask)) < 0) { inet_aftype.herror(netmask); return (E_LOOKUP); } rt.rt_genmask = full_mask(mask); args++; continue; } if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) { args++; if (!*args) return usage(E_OPTERR); if (rt.rt_flags & RTF_GATEWAY) return usage(E_OPTERR); safe_strncpy(gateway, *args, (sizeof gateway)); if ((isnet = inet_aftype.input(256, gateway, &rt.rt_gateway)) < 0) { inet_aftype.herror(gateway); return (E_LOOKUP); } if (isnet) { fprintf(stderr, _("route: %s: cannot use a NETWORK as gateway!\n"), gateway); return usage(E_OPTERR); } rt.rt_flags |= RTF_GATEWAY; args++; continue; } if (!strcmp(*args, "mss") || !strcmp(*args,"mtu")) { args++; rt.rt_flags |= RTF_MSS; if (!*args) return usage(E_OPTERR); rt.rt_mss = atoi(*args); args++; if (rt.rt_mss < 64 || rt.rt_mss > 65536) { fprintf(stderr, _("route: Invalid MSS/MTU.\n")); return usage(E_OPTERR); } continue; } if (!strcmp(*args, "window")) { args++; if (!*args) return usage(E_OPTERR); rt.rt_flags |= RTF_WINDOW; rt.rt_window = atoi(*args); args++; if (rt.rt_window < 128) { fprintf(stderr, _("route: Invalid window.\n")); return usage(E_OPTERR); } continue; } if (!strcmp(*args, "irtt")) { args++; if (!*args) return usage(E_OPTERR); args++; #if HAVE_RTF_IRTT rt.rt_flags |= RTF_IRTT; rt.rt_irtt = atoi(*(args - 1)); rt.rt_irtt *= (HZ / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { fprintf(stderr, _("route: Invalid initial rtt.\n")); return usage(E_OPTERR); } #endif #else ENOSUPP("inet_setroute", "RTF_IRTT"); #endif continue; } if (!strcmp(*args, "reject")) { args++; #if HAVE_RTF_REJECT rt.rt_flags |= RTF_REJECT; #else ENOSUPP("inet_setroute", "RTF_REJECT"); #endif continue; } if (!strcmp(*args, "mod")) { args++; rt.rt_flags |= RTF_MODIFIED; continue; } if (!strcmp(*args, "dyn")) { args++; rt.rt_flags |= RTF_DYNAMIC; continue; } if (!strcmp(*args, "reinstate")) { args++; rt.rt_flags |= RTF_REINSTATE; continue; } if (!strcmp(*args, "device") || !strcmp(*args, "dev")) { args++; if (rt.rt_dev || *args == NULL) return usage(E_OPTERR); rt.rt_dev = *args++; continue; } /* nothing matches */ if (!rt.rt_dev) { rt.rt_dev = *args++; if (*args) return usage(E_OPTERR); /* must be last to catch typos */ } else return usage(E_OPTERR); } #if HAVE_RTF_REJECT if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) rt.rt_dev = "lo"; #endif /* sanity checks.. */ if (mask_in_addr(rt)) { __u32 mask = ~ntohl(mask_in_addr(rt)); if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { fprintf(stderr, _("route: netmask %.8x doesn't make sense with host route\n"), mask); return usage(E_OPTERR); } if (mask & (mask + 1)) { fprintf(stderr, _("route: bogus netmask %s\n"), netmask); return usage(E_OPTERR); } mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; if (mask & ~mask_in_addr(rt)) { fprintf(stderr, _("route: netmask doesn't match route address\n")); return usage(E_OPTERR); } } /* Fill out netmask if still unset */ if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) mask_in_addr(rt) = 0xffffffff; /* Create a socket to the INET kernel. */ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return (E_SOCK); } /* Tell the kernel to accept this route. */ if (action == RTACTION_DEL) { if (ioctl(skfd, SIOCDELRT, &rt) < 0) { perror("SIOCDELRT"); close(skfd); return (E_SOCK); } } else { if (ioctl(skfd, SIOCADDRT, &rt) < 0) { perror("SIOCADDRT"); close(skfd); return (E_SOCK); } } /* Close the socket. */ (void) close(skfd); return (0); }
static void INET_setroute(int action, char **args) { struct rtentry rt; const char *netmask; int skfd, isnet, xflag; assert((action == RTACTION_ADD) || (action == RTACTION_DEL)); /* Grab the -net or -host options. Remember they were transformed. */ xflag = kw_lookup(tbl_hash_net_host, &args); /* If we did grab -net or -host, make sure we still have an arg left. */ if (*args == NULL) { bb_show_usage(); } /* Clean out the RTREQ structure. */ memset((char *) &rt, 0, sizeof(struct rtentry)); { const char *target = *args++; /* Prefer hostname lookup is -host flag (xflag==1) was given. */ isnet = INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst, (xflag & HOST_FLAG)); if (isnet < 0) { bb_error_msg_and_die("resolving %s", target); } } if (xflag) { /* Reinit isnet if -net or -host was specified. */ isnet = (xflag & NET_FLAG); } /* Fill in the other fields. */ rt.rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST)); netmask = bb_INET_default; while (*args) { int k = kw_lookup(tbl_ipvx, &args); const char *args_m1 = args[-1]; if (k & KW_IPVx_FLAG_ONLY) { rt.rt_flags |= flags_ipvx[k & 3]; continue; } #if HAVE_NEW_ADDRT if (k == KW_IPVx_METRIC) { rt.rt_metric = bb_xgetularg10(args_m1) + 1; continue; } #endif if (k == KW_IPVx_NETMASK) { struct sockaddr mask; if (mask_in_addr(rt)) { bb_show_usage(); } netmask = args_m1; isnet = INET_resolve(netmask, (struct sockaddr_in *) &mask, 0); if (isnet < 0) { bb_error_msg_and_die("resolving %s", netmask); } rt.rt_genmask = full_mask(mask); continue; } if (k == KW_IPVx_GATEWAY) { if (rt.rt_flags & RTF_GATEWAY) { bb_show_usage(); } isnet = INET_resolve(args_m1, (struct sockaddr_in *) &rt.rt_gateway, 1); rt.rt_flags |= RTF_GATEWAY; if (isnet) { if (isnet < 0) { bb_error_msg_and_die("resolving %s", args_m1); } bb_error_msg_and_die("gateway %s is a NETWORK", args_m1); } continue; } if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */ rt.rt_flags |= RTF_MSS; rt.rt_mss = bb_xgetularg10_bnd(args_m1, 64, 32768); continue; } if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */ rt.rt_flags |= RTF_WINDOW; rt.rt_window = bb_xgetularg10_bnd(args_m1, 128, INT_MAX); continue; } #ifdef RTF_IRTT if (k == KW_IPVx_IRTT) { rt.rt_flags |= RTF_IRTT; rt.rt_irtt = bb_xgetularg10(args_m1); rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { bb_error_msg_and_die("bad irtt"); } #endif continue; } #endif /* Device is special in that it can be the last arg specified * and doesn't requre the dev/device keyword in that case. */ if (!rt.rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ rt.rt_dev = args[-1]; continue; } /* Nothing matched. */ bb_show_usage(); } #ifdef RTF_REJECT if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) { rt.rt_dev = "lo"; } #endif /* sanity checks.. */ if (mask_in_addr(rt)) { unsigned long mask = mask_in_addr(rt); mask = ~ntohl(mask); if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { bb_error_msg_and_die("netmask %.8x and host route conflict", (unsigned int) mask); } if (mask & (mask + 1)) { bb_error_msg_and_die("bogus netmask %s", netmask); } mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; if (mask & ~mask_in_addr(rt)) { bb_error_msg_and_die("netmask and route address conflict"); } } /* Fill out netmask if still unset */ if ((action == RTACTION_ADD) && (rt.rt_flags & RTF_HOST)) { mask_in_addr(rt) = 0xffffffff; } /* Create a socket to the INET kernel. */ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { bb_perror_msg_and_die("socket"); } if (ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0) { bb_perror_msg_and_die("SIOC[ADD|DEL]RT"); } /* Don't bother closing, as we're exiting after we return anyway. */ /* close(skfd); */ }
static int INET_setroute(int action, int options, char **args) { struct rtentry rt; char target[128], gateway[128] = "NONE"; const char *netmask = bb_INET_default; int xflag, isnet; int skfd; xflag = 0; if (*args == NULL) bb_show_usage(); if (strcmp(*args, "-net") == 0) { xflag = 1; args++; } else if (strcmp(*args, "-host") == 0) { xflag = 2; args++; } if (*args == NULL) bb_show_usage(); safe_strncpy(target, *args++, (sizeof target)); /* Clean out the RTREQ structure. */ memset((char *) &rt, 0, sizeof(struct rtentry)); if ((isnet = INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst, xflag != 1)) < 0) { bb_error_msg(_("can't resolve %s"), target); return EXIT_FAILURE; /* XXX change to E_something */ } switch (xflag) { case 1: isnet = 1; break; case 2: isnet = 0; break; default: break; } /* Fill in the other fields. */ rt.rt_flags = (RTF_UP | RTF_HOST); if (isnet) rt.rt_flags &= ~RTF_HOST; while (*args) { if (strcmp(*args, "metric") == 0) { int metric; args++; if (!*args || !isdigit(**args)) bb_show_usage(); metric = atoi(*args); #if HAVE_NEW_ADDRT rt.rt_metric = metric + 1; #else ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */ #endif args++; continue; } if (strcmp(*args, "netmask") == 0) { struct sockaddr mask; args++; if (!*args || mask_in_addr(rt)) bb_show_usage(); netmask = *args; if ((isnet = INET_resolve(netmask, (struct sockaddr_in *) &mask, 0)) < 0) { bb_error_msg(_("can't resolve netmask %s"), netmask); return E_LOOKUP; } rt.rt_genmask = full_mask(mask); args++; continue; } if (strcmp(*args, "gw") == 0 || strcmp(*args, "gateway") == 0) { args++; if (!*args) bb_show_usage(); if (rt.rt_flags & RTF_GATEWAY) bb_show_usage(); safe_strncpy(gateway, *args, (sizeof gateway)); if ((isnet = INET_resolve(gateway, (struct sockaddr_in *) &rt.rt_gateway, 1)) < 0) { bb_error_msg(_("can't resolve gw %s"), gateway); return E_LOOKUP; } if (isnet) { bb_error_msg(_("%s: cannot use a NETWORK as gateway!"), gateway); return E_OPTERR; } rt.rt_flags |= RTF_GATEWAY; args++; continue; } if (strcmp(*args, "mss") == 0) { args++; rt.rt_flags |= RTF_MSS; if (!*args) bb_show_usage(); rt.rt_mss = atoi(*args); args++; if (rt.rt_mss < 64 || rt.rt_mss > 32768) { bb_error_msg(_("Invalid MSS.")); return E_OPTERR; } continue; } if (strcmp(*args, "window") == 0) { args++; if (!*args) bb_show_usage(); rt.rt_flags |= RTF_WINDOW; rt.rt_window = atoi(*args); args++; if (rt.rt_window < 128) { bb_error_msg(_("Invalid window.")); return E_OPTERR; } continue; } if (strcmp(*args, "irtt") == 0) { args++; if (!*args) bb_show_usage(); args++; #if HAVE_RTF_IRTT rt.rt_flags |= RTF_IRTT; rt.rt_irtt = atoi(*(args - 1)); rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { bb_error_msg(_("Invalid initial rtt.")); return E_OPTERR; } #endif #else ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */ #endif continue; } if (strcmp(*args, "reject") == 0) { args++; #if HAVE_RTF_REJECT rt.rt_flags |= RTF_REJECT; #else ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */ #endif continue; } if (strcmp(*args, "mod") == 0) { args++; rt.rt_flags |= RTF_MODIFIED; continue; } if (strcmp(*args, "dyn") == 0) { args++; rt.rt_flags |= RTF_DYNAMIC; continue; } if (strcmp(*args, "reinstate") == 0) { args++; rt.rt_flags |= RTF_REINSTATE; continue; } if (strcmp(*args, "device") == 0 || strcmp(*args, "dev") == 0) { args++; if (rt.rt_dev || *args == NULL) bb_show_usage(); rt.rt_dev = *args++; continue; } /* nothing matches */ if (!rt.rt_dev) { rt.rt_dev = *args++; if (*args) bb_show_usage(); /* must be last to catch typos */ } else { bb_show_usage(); } } #if HAVE_RTF_REJECT if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) rt.rt_dev = "lo"; #endif /* sanity checks.. */ if (mask_in_addr(rt)) { unsigned long mask = mask_in_addr(rt); mask = ~ntohl(mask); if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { bb_error_msg(_("netmask %.8x doesn't make sense with host route"), (unsigned int) mask); return E_OPTERR; } if (mask & (mask + 1)) { bb_error_msg(_("bogus netmask %s"), netmask); return E_OPTERR; } mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; if (mask & ~mask_in_addr(rt)) { bb_error_msg(_("netmask doesn't match route address")); return E_OPTERR; } } /* Fill out netmask if still unset */ if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) mask_in_addr(rt) = 0xffffffff; /* Create a socket to the INET kernel. */ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return E_SOCK; } /* Tell the kernel to accept this route. */ if (action == RTACTION_DEL) { if (ioctl(skfd, SIOCDELRT, &rt) < 0) { perror("SIOCDELRT"); close(skfd); return E_SOCK; } } else { if (ioctl(skfd, SIOCADDRT, &rt) < 0) { perror("SIOCADDRT"); close(skfd); return E_SOCK; } } /* Close the socket. */ (void) close(skfd); return EXIT_SUCCESS; }