int delete_route(char *address, int netmask) { struct rtnl_handle rth = { .fd = -1 }; if (rtnl_open(&rth, 0) < 0) { exit(1); } struct iplink_req req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = RTM_DELROUTE; req.rtm.rtm_family = AF_UNSPEC; req.rtm.rtm_table = RT_TABLE_MAIN; req.rtm.rtm_scope = RT_SCOPE_NOWHERE; inet_prefix dst; get_prefix(&dst, address, req.rtm.rtm_family); req.rtm.rtm_family = dst.family; if (req.rtm.rtm_family == AF_UNSPEC) { req.rtm.rtm_family = AF_INET; } req.rtm.rtm_dst_len = netmask; if (dst.bytelen) { addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); } ll_init_map(&rth); struct nlmsghdr *answer; int errnum = rtnl_talkE(&rth, &req.n, 0, 0, &answer, NULL, NULL); if (errnum < 0) { exit(2); } if (answer) { switch (errnum) { case 0: // Success fprintf(stderr, "delete route to %s\n", address); break; case 3: // No such device // fprintf(stderr, "already deleted.\n"); break; default: fprintf(stderr, "ERROR!\terrno: %d\n", errnum); perror("Netlink"); exit(2); break; } } else { fprintf(stderr, "Something Wrong!\n"); exit(2); } return 0; } int delete_all_route() { struct rtnl_handle rth = { .fd = -1 }; if (rtnl_open(&rth, 0) < 0) { exit(1); } int preferred_family = AF_PACKET; if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETROUTE) < 0) { perror("Cannot send dump request"); exit(1); } struct nlmsg_list *rinfo = NULL; if (rtnl_dump_filter(&rth, store_nlmsg, &rinfo, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } struct nlmsg_list *r, *n; for (r = rinfo; r; r = n) { n = r->next; struct nlmsghdr *nlhdr = &(r->h); if (nlhdr->nlmsg_type != RTM_NEWROUTE && nlhdr->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", nlhdr->nlmsg_len, nlhdr->nlmsg_type, nlhdr->nlmsg_flags); return 0; } struct rtmsg *rtm = NLMSG_DATA(nlhdr); int len = nlhdr->nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } // Analyze rtattr Message struct rtattr *tb[RTA_MAX + 1]; parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); char dst_address[64] = ""; char abuf[256]; int host_len = calc_host_len(rtm); if (tb[RTA_DST]) { if (rtm->rtm_dst_len != host_len) { sprintf(dst_address, "%s/%d", rt_addr_n2a(rtm->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), rtm->rtm_dst_len); } else { sprintf(dst_address, "%s", format_host(rtm->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf))); } } else if (rtm->rtm_dst_len) { sprintf(dst_address, "0/%d", rtm->rtm_dst_len); } else { sprintf(dst_address, "default"); } if (strncmp(dst_address, "127.0.0.0", 9) != 0 && strcmp(dst_address, "ff00::") != 0) { delete_route((char *) dst_address, rtm->rtm_dst_len); } } printf("delete all routes.\n\n"); free(r); rtnl_close(&rth); return 0; } // network is unreachableを回避するため、全経路を登録し終えるまでwhileループを回す void modify_route(json_t *ipRouteEntry_json, int default_flag) { int end = 0; while (end == 0) { end = 1; int i; for (i = 0; i < (int) json_array_size(ipRouteEntry_json); i++) { json_t *route_json = json_array_get(ipRouteEntry_json, i); json_t *linux_json = json_object_get(route_json, "linux"); struct rtnl_handle rth = { .fd = -1 }; if (rtnl_open(&rth, 0) < 0) { exit(1); } struct iplink_req req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWROUTE; req.rtm.rtm_family = AF_UNSPEC; req.rtm.rtm_type = (int) json_number_value(json_object_get(route_json, "ipRouteType")); if (req.rtm.rtm_type >= 5) { // 5以降は定義されていない req.rtm.rtm_type = 1; } req.rtm.rtm_protocol = (int) json_number_value(json_object_get(route_json, "ipRouteProto")); req.rtm.rtm_scope = (int) json_number_value(json_object_get(linux_json, "rtm_scope")); req.rtm.rtm_table = (int) json_number_value(json_object_get(linux_json, "rtm_table")); req.rtm.rtm_dst_len = (int) json_number_value(json_object_get(route_json, "ipRouteMask")); char *route_name = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"; const char *key; json_t *value; json_object_foreach(route_json, key, value) { if (strcmp(key, "ipRouteDest") == 0) { inet_prefix dst; route_name = (char *) json_string_value(value); get_prefix(&dst, route_name, req.rtm.rtm_family); if (req.rtm.rtm_family == AF_UNSPEC) { req.rtm.rtm_family = dst.family; } if (dst.bytelen) { addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); } } if (strcmp(key, "ipRouteIfIndex") == 0) { addattr32(&req.n, sizeof(req), RTA_OIF, json_integer_value(value)); } if (strcmp(key, "ipRouteNextHop") == 0) { inet_prefix addr; get_addr(&addr, (char *) json_string_value(value), req.rtm.rtm_family); if (req.rtm.rtm_family == AF_UNSPEC) { req.rtm.rtm_family = addr.family; } addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); } if (strcmp(key, "ipRouteMetric1") == 0) { addattr32(&req.n, sizeof(req), RTA_PRIORITY, json_integer_value(value)); } if (strcmp(key, "ipRouteInfo") == 0) { inet_prefix addr; get_addr(&addr, (char *) json_string_value(value), req.rtm.rtm_family); if (req.rtm.rtm_family == AF_UNSPEC) { req.rtm.rtm_family = addr.family; } addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); } } ll_init_map(&rth); if (req.rtm.rtm_family == AF_UNSPEC) { req.rtm.rtm_family = AF_INET; } struct nlmsghdr *answer; int errnum = rtnl_talkE(&rth, &req.n, 0, 0, &answer, NULL, NULL); if (errnum < 0) { exit(2); } if (answer) { switch (errnum) { case 0: // Success fprintf(stderr, "arrange route to %s/%d\n", route_name, req.rtm.rtm_dst_len); break; case 17: // File exists // fprintf(stderr, "route already exists.\n"); break; case 19: // No such device // fprintf(stderr, "No such device"); break; case 101: // Network is unreachable end = 0; break; default: fprintf(stderr, "ERROR!\terrno: %d\n", errnum); perror("Netlink"); exit(2); break; } } else { fprintf(stderr, "Something Wrong!\n"); exit(2); } } } } int read_route_file(json_t *routes_json) { // routeの削除 delete_all_route(); json_t *ipRouteEntry_json = json_object_get(routes_json, "ipRouteEntry"); // defaultへの経路はGatewayへの経路が登録されてからでないとnetwork is unreachableになるので // defaultへの経路とそうでないものを分ける modify_route(ipRouteEntry_json, 0); modify_route(ipRouteEntry_json, 1); fprintf(stderr, "Success arranging all routes!\n\n"); return 0; }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; int host_len = -1; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } host_len = calc_host_len(r); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (!filter_nlmsg(n, tb, host_len)) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if (r->rtm_type != RTN_UNICAST && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (!(r->rtm_flags&RTM_F_CLONED)) { if (table != RT_TABLE_MAIN && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (tb[RTA_MARK]) { unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]); if (mark) { if (mark >= 16) fprintf(fp, " mark 0x%x", mark); else fprintf(fp, " mark %u", mark); } } if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }