Example #1
0
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;
}
Example #2
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)));
	}