static int INET6_input(int type, char *bufp, struct sockaddr *sap) { switch (type) { case 1: return (INET6_getsock(bufp, sap)); default: return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); } }
static void INET6_setroute(int action, char **args) { struct sockaddr_in6 sa6; struct in6_rtmsg rt; int prefix_len, skfd; const char *devname; assert((action == RTACTION_ADD) || (action == RTACTION_DEL)); { /* We know args isn't NULL from the check in route_main. */ const char *target = *args++; if (strcmp(target, "default") == 0) { prefix_len = 0; memset(&sa6, 0, sizeof(sa6)); } else { char *cp; if ((cp = strchr(target, '/'))) { /* Yes... const to non is ok. */ *cp = 0; prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128); } else { prefix_len = 128; } if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) { bb_error_msg_and_die("resolving %s", target); } } } /* Clean out the RTREQ structure. */ memset((char *) &rt, 0, sizeof(struct in6_rtmsg)); memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); /* Fill in the other fields. */ rt.rtmsg_dst_len = prefix_len; rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP); rt.rtmsg_metric = 1; devname = NULL; while (*args) { int k = kw_lookup(tbl_ipvx, &args); const char *args_m1 = args[-1]; if ((k == KW_IPVx_MOD) || (k == KW_IPVx_DYN)) { rt.rtmsg_flags |= flags_ipvx[k & 3]; continue; } if (k == KW_IPVx_METRIC) { rt.rtmsg_metric = bb_xgetularg10(args_m1); continue; } if (k == KW_IPVx_GATEWAY) { if (rt.rtmsg_flags & RTF_GATEWAY) { bb_show_usage(); } if (INET6_resolve(args_m1, (struct sockaddr_in6 *) &sa6) < 0) { bb_error_msg_and_die("resolving %s", args_m1); } memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); rt.rtmsg_flags |= RTF_GATEWAY; continue; } /* Device is special in that it can be the last arg specified * and doesn't requre the dev/device keyword in that case. */ if (!devname && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ devname = args[-1]; continue; } /* Nothing matched. */ bb_show_usage(); } /* Create a socket to the INET6 kernel. */ if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { bb_perror_msg_and_die("socket"); } rt.rtmsg_ifindex = 0; if (devname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, devname); if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) { bb_perror_msg_and_die("SIOGIFINDEX"); } rt.rtmsg_ifindex = ifr.ifr_ifindex; } /* Tell the kernel to accept this route. */ 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 INET6_setroute(int action, int options, char **args) { struct in6_rtmsg rt; struct ifreq ifr; struct sockaddr_in6 sa6; char target[128], gateway[128] = "NONE"; int metric, prefix_len; char *devname = NULL; char *cp; int skfd; if (*args == NULL) bb_show_usage(); strcpy(target, *args++); if (!strcmp(target, "default")) { prefix_len = 0; memset(&sa6, 0, sizeof(sa6)); } else { if ((cp = strchr(target, '/'))) { prefix_len = atol(cp + 1); if ((prefix_len < 0) || (prefix_len > 128)) bb_show_usage(); *cp = 0; } else { prefix_len = 128; } if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) { bb_error_msg(_("can't resolve %s"), target); return EXIT_FAILURE; /* XXX change to E_something */ } } /* Clean out the RTREQ structure. */ memset((char *) &rt, 0, sizeof(struct in6_rtmsg)); memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); /* Fill in the other fields. */ rt.rtmsg_flags = RTF_UP; if (prefix_len == 128) rt.rtmsg_flags |= RTF_HOST; rt.rtmsg_metric = 1; rt.rtmsg_dst_len = prefix_len; while (*args) { if (!strcmp(*args, "metric")) { args++; if (!*args || !isdigit(**args)) bb_show_usage(); metric = atoi(*args); rt.rtmsg_metric = metric; args++; continue; } if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) { args++; if (!*args) bb_show_usage(); if (rt.rtmsg_flags & RTF_GATEWAY) bb_show_usage(); strcpy(gateway, *args); if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) { bb_error_msg(_("can't resolve gw %s"), gateway); return (E_LOOKUP); } memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); rt.rtmsg_flags |= RTF_GATEWAY; args++; continue; } if (!strcmp(*args, "mod")) { args++; rt.rtmsg_flags |= RTF_MODIFIED; continue; } if (!strcmp(*args, "dyn")) { args++; rt.rtmsg_flags |= RTF_DYNAMIC; continue; } if (!strcmp(*args, "device") || !strcmp(*args, "dev")) { args++; if (!*args) bb_show_usage(); } else if (args[1]) bb_show_usage(); devname = *args; args++; } /* Create a socket to the INET6 kernel. */ if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("socket"); return (E_SOCK); } if (devname) { memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, devname); if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) { perror("SIOGIFINDEX"); return (E_SOCK); } rt.rtmsg_ifindex = ifr.ifr_ifindex; } else rt.rtmsg_ifindex = 0; /* 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); }