예제 #1
0
static int do_address(const char *ifname,
                      struct in_addr address, struct in_addr netmask,
                      struct in_addr broadcast, int del)
{
    struct
    {
        struct nlmsghdr hdr;
        struct ifaddrmsg ifa;
        char buffer[64];
    }
    nlm;

    if (!ifname)
        return -1;

    memset (&nlm, 0, sizeof (nlm));

    nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
    nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
    if (! del)
        nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
    nlm.hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR;
    nlm.ifa.ifa_index = if_nametoindex (ifname);
    nlm.ifa.ifa_family = AF_INET;

    nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask);
    add_attr_l (&nlm.hdr, sizeof (nlm), IFA_LOCAL, &address.s_addr,
                sizeof (address.s_addr));
    if (! del)
        add_attr_l (&nlm.hdr, sizeof (nlm), IFA_BROADCAST, &broadcast.s_addr,
                    sizeof (broadcast.s_addr));

    return send_netlink (&nlm.hdr);
}
예제 #2
0
int
if_address(const struct interface *iface,
    const struct in_addr *address, const struct in_addr *netmask,
    const struct in_addr *broadcast, int action)
{
	struct nlma *nlm;
	int retval = 0;

	nlm = calloc(1, sizeof(*nlm));
	if (nlm == NULL)
		return -1;
	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
	if (action >= 0) {
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
		nlm->hdr.nlmsg_type = RTM_NEWADDR;
	} else
		nlm->hdr.nlmsg_type = RTM_DELADDR;
	nlm->ifa.ifa_index = iface->index;
	nlm->ifa.ifa_family = AF_INET;
	nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
	/* This creates the aliased interface */
	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
	    iface->name, strlen(iface->name) + 1);
	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
	    &address->s_addr, sizeof(address->s_addr));
	if (action >= 0 && broadcast)
		add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
		    &broadcast->s_addr, sizeof(broadcast->s_addr));

	if (send_netlink(&nlm->hdr) == -1)
		retval = -1;
	free(nlm);
	return retval;
}
예제 #3
0
int add_address (const char *ifname, struct in_addr address,
                 struct in_addr netmask, struct in_addr broadcast)
{
    logger (LOG_INFO, "adding IP address %s/%d",
            inet_ntoa (address), inet_ntocidr (netmask));

    return (do_address (ifname, address, netmask, broadcast, 0));
}
예제 #4
0
static void log_route( 
					  struct in_addr destination,
					  struct in_addr netmask,
					  struct in_addr gateway,
					  int metric,
					  int change, int del)
{
	char *dstd = xstrdup (inet_ntoa (destination));

#ifdef __linux__
#define METRIC " metric %d"
#else
#define METRIC ""
	metric = 0;
#endif

	if (gateway.s_addr == destination.s_addr ||
		gateway.s_addr == INADDR_ANY)
		logger (LOG_INFO, "%s route to %s/%d" METRIC,
				change ? "changing" : del ? "removing" : "adding",
				dstd, inet_ntocidr (netmask)
#ifdef __linux__
				, metric
#endif
			   );
	else if (destination.s_addr == INADDR_ANY)
		logger (LOG_INFO, "%s default route via %s" METRIC,
				change ? "changing" : del ? "removing" : "adding",
				inet_ntoa (gateway)

#ifdef __linux__
				, metric
#endif
			   );
	else
		logger (LOG_INFO, "%s route to %s/%d via %s" METRIC,
				change ? "changing" : del ? "removing" : "adding",
				dstd, inet_ntocidr (netmask), inet_ntoa (gateway)
#ifdef __linux__
				, metric
#endif
			   );

	free (dstd);
}
예제 #5
0
int del_address (const char *ifname,
                 struct in_addr address, struct in_addr netmask)
{
    struct in_addr t;

    logger (LOG_INFO, "deleting IP address %s/%d",
            inet_ntoa (address), inet_ntocidr (netmask));

    memset (&t, 0, sizeof (t));
    return (do_address (ifname, address, netmask, t, 1));
}
예제 #6
0
static int do_address(const char *ifname,
					  struct in_addr address, struct in_addr netmask,
					  struct in_addr broadcast, int del)
{
	struct nlma *nlm;
	int retval;

	if (!ifname)
		return -1;

	nlm = xmalloc (sizeof (struct nlma));
	memset (nlm, 0, sizeof (struct nlma));

	nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
	nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
	if (! del)
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
	nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR;
	if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) {
		logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
				ifname);
		free (nlm);
		return -1;
	}
	nlm->ifa.ifa_family = AF_INET;

	nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask);

	/* This creates the aliased interface */
	add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_LABEL,
				ifname, strlen (ifname) + 1);

	add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_LOCAL,
				&address.s_addr, sizeof (address.s_addr));
	if (! del)
		add_attr_l (&nlm->hdr, sizeof (struct nlma), IFA_BROADCAST,
					&broadcast.s_addr, sizeof (broadcast.s_addr));

	retval = send_netlink (&nlm->hdr);
	free (nlm);
	return retval;
}
int
if_route(const char *ifname,
	 const struct in_addr *destination, const struct in_addr *netmask,
	 const struct in_addr *gateway, int metric, int action)
{
	struct nlmr *nlm;
	unsigned int ifindex;
	int retval = 0;


	if (!(ifindex = if_nametoindex(ifname))) {
		errno = ENODEV;
		return -1;
	}

	nlm = xzalloc(sizeof(*nlm));
	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
	if (action == 0)
            nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
	else if (action > 0)
		/*
		 * ers@google:
		 * commented out NLM_F_EXCL here and below. We
		 * sometimes keep one interface up while we are
		 * configuring the other one, and this flag
		 * causes route addition to fail.
		 */
		nlm->hdr.nlmsg_flags = NLM_F_CREATE /* | NLM_F_EXCL */;
	else
		nlm->hdr.nlmsg_type = RTM_DELROUTE;
	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
	nlm->rt.rtm_family = AF_INET;
	nlm->rt.rtm_table = RT_TABLE_MAIN;

	if (action < 0)
		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
	else {
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
		nlm->rt.rtm_protocol = RTPROT_BOOT;
		if (gateway->s_addr == INADDR_ANY)
			nlm->rt.rtm_scope = RT_SCOPE_LINK;
		else
			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
		nlm->rt.rtm_type = RTN_UNICAST;
	}

	nlm->rt.rtm_dst_len = inet_ntocidr(*netmask);
	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
		   &destination->s_addr, sizeof(destination->s_addr));
	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
		   &gateway->s_addr, sizeof(gateway->s_addr));

	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, metric);

	if (send_netlink(&nlm->hdr) == -1)
		retval = -1;
	free(nlm);
	return retval;
}
예제 #8
0
static int do_route (const char *ifname,
                     struct in_addr destination,
                     struct in_addr netmask,
                     struct in_addr gateway,
                     int metric, int change, int del)
{
    char *dstd;
    char *gend;
    struct
    {
        struct nlmsghdr hdr;
        struct rtmsg rt;
        char buffer[256];
    }
    nlm;

    if (! ifname)
        return -1;

    dstd = strdup (inet_ntoa (destination));
    gend = strdup (inet_ntoa (netmask));
    if (gateway.s_addr == destination.s_addr)
        logger (LOG_INFO, "%s route to %s (%s) metric %d",
                change ? "changing" : del ? "removing" : "adding",
                dstd, gend, metric);
    else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
        logger (LOG_INFO, "%s default route via %s metric %d",
                change ? "changing" : del ? "removing" : "adding",
                inet_ntoa (gateway), metric);
    else
        logger (LOG_INFO, "%s route to %s (%s) via %s metric %d",
                change ? "changing" : del ? "removing" : "adding",
                dstd, gend, inet_ntoa (gateway), metric);
    if (dstd)
        free (dstd);
    if (gend)
        free (gend);

    memset (&nlm, 0, sizeof (nlm));

    nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
    if (change)
        nlm.hdr.nlmsg_flags = NLM_F_REPLACE;
    else if (! del)
        nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
    nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
    nlm.hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE;
    nlm.rt.rtm_family = AF_INET;
    nlm.rt.rtm_table = RT_TABLE_MAIN;

    if (del)
        nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
    else
    {
        nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
        nlm.rt.rtm_protocol = RTPROT_BOOT;
        if (gateway.s_addr == INADDR_ANY ||
                netmask.s_addr == INADDR_BROADCAST)
            nlm.rt.rtm_scope = RT_SCOPE_LINK;
        else
            nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
        nlm.rt.rtm_type = RTN_UNICAST;
    }

    nlm.rt.rtm_dst_len = inet_ntocidr (netmask);
    add_attr_l (&nlm.hdr, sizeof (nlm), RTA_DST, &destination.s_addr,
                sizeof (destination.s_addr));
    if (gateway.s_addr != INADDR_ANY && gateway.s_addr != destination.s_addr)
        add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr,
                    sizeof (gateway.s_addr));

    add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, if_nametoindex (ifname));
    add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric);

    return send_netlink (&nlm.hdr);
}
예제 #9
0
static int do_route (const char *ifname,
                     struct in_addr destination,
                     struct in_addr netmask,
                     struct in_addr gateway,
                     int metric,
                     int change, int del)
{
    int s;
    char *dstd;
    char *gend;
    struct rtm
    {
        struct rt_msghdr hdr;
        struct sockaddr_in destination;
        union
        {
            struct sockaddr sa;
            struct sockaddr_in sin;
            struct sockaddr_dl sdl;
            struct sockaddr_storage sss; /* added to avoid memory overrun */
        } gateway;
        struct sockaddr_in netmask;
    } rtm;
    static int seq;

    if (! ifname)
        return -1;

    /* Do something with metric to satisfy compiler warnings */
    metric = 0;

    dstd = strdup (inet_ntoa (destination));
    if (gateway.s_addr == destination.s_addr)
        logger (LOG_INFO, "%s route to %s/%d",
                change ? "changing" : del ? "removing" : "adding",
                dstd, gend, inet_ntocidr (netmask));
    else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
        logger (LOG_INFO, "%s default route via %s",
                change ? "changing" : del ? "removing" : "adding",
                inet_ntoa (gateway));
    else
        logger (LOG_INFO, "%s route to %s/%d via %s",
                change ? "changing" : del ? "removing" : "adding",
                dstd, inet_ntocidr (netmask), inet_ntoa (gateway));
    if (dstd)
        free (dstd);

    if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
    {
        logger (LOG_ERR, "socket: %s", strerror (errno));
        return -1;
    }

    memset (&rtm, 0, sizeof (struct rtm));

    rtm.hdr.rtm_version = RTM_VERSION;
    rtm.hdr.rtm_seq = ++seq;
    rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD;

    rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
    if (netmask.s_addr == INADDR_BROADCAST)
        rtm.hdr.rtm_flags |= RTF_HOST;
    else
        rtm.hdr.rtm_flags |= RTF_GATEWAY;

    rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;

#define ADDADDR(_var, _addr) \
  _var.sin_family = AF_INET; \
  _var.sin_len = sizeof (struct sockaddr_in); \
  memcpy (&_var.sin_addr, &_addr, sizeof (struct in_addr));

    ADDADDR (rtm.destination, destination);
    if (netmask.s_addr == INADDR_BROADCAST)
    {
        struct ifaddrs *ifap, *ifa;
        union
        {
            struct sockaddr *sa;
            struct sockaddr_dl *sdl;
        } us;

        if (getifaddrs (&ifap))
        {
            logger (LOG_ERR, "getifaddrs: %s", strerror (errno));
            return -1;
        }

        for (ifa = ifap; ifa; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr->sa_family != AF_LINK)
                continue;

            if (strcmp (ifname, ifa->ifa_name))
                continue;

            us.sa = ifa->ifa_addr;
            memcpy (&rtm.gateway.sdl, us.sdl, us.sdl->sdl_len);
            break;
        }
        freeifaddrs (ifap);
    }
    else
    {
        ADDADDR (rtm.gateway.sin, gateway);
    }

    ADDADDR (rtm.netmask, netmask);

#undef ADDADDR

    rtm.hdr.rtm_msglen = sizeof (rtm);

    if (write(s, &rtm, sizeof (rtm)) < 0)
    {
        /* Don't report error about routes already existing */
        if (errno != EEXIST)
            logger (LOG_ERR, "write: %s", strerror (errno));
        close (s);
        return -1;
    }

    close (s);
    return 0;
}
예제 #10
0
ssize_t
configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
	      const struct options *options)
{
	unsigned int i;
	const uint8_t *p;
	int pl;
	struct in_addr addr;
	struct in_addr net;
	struct in_addr brd;
	char *val, *v;
	const struct dhcp_opt *opt;
	ssize_t len, e = 0;
	char **ep;
	char cidr[4];
	uint8_t overl = 0;

	get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);

	if (!env) {
		for (opt = dhcp_opts; opt->option; opt++) {
			if (!opt->var)
				continue;
			if (has_option_mask(options->nomask, opt->option))
				continue;
			if (get_option_raw(dhcp, opt->option))
				e++;
		}
		if (dhcp->yiaddr)
			e += 5;
		if (*dhcp->bootfile && !(overl & 1))
			e++;
		if (*dhcp->servername && !(overl & 2))
			e++;
		return e;
	}

	ep = env;
	if (dhcp->yiaddr) {
		/* Set some useful variables that we derive from the DHCP
		 * message but are not necessarily in the options */
		addr.s_addr = dhcp->yiaddr;
		setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
		if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
			net.s_addr = get_netmask(addr.s_addr);
			setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
		}
		i = inet_ntocidr(net);
		snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
		setvar(&ep, prefix, "subnet_cidr", cidr);
		if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) {
			brd.s_addr = addr.s_addr | ~net.s_addr;
			setvar(&ep, prefix, "broadcast_address", inet_ntoa(brd));
		}
		addr.s_addr = dhcp->yiaddr & net.s_addr;
		setvar(&ep, prefix, "network_number", inet_ntoa(addr));
	}

	if (*dhcp->bootfile && !(overl & 1))
		setvar(&ep, prefix, "filename", (const char *)dhcp->bootfile);
	if (*dhcp->servername && !(overl & 2))
		setvar(&ep, prefix, "server_name", (const char *)dhcp->servername);

	for (opt = dhcp_opts; opt->option; opt++) {
		if (!opt->var)
			continue;
		if (has_option_mask(options->nomask, opt->option))
			continue;
		val = NULL;
		p = get_option(dhcp, opt->option, &pl, NULL);
		if (!p)
			continue;
		/* We only want the FQDN name */
		if (opt->option == DHO_FQDN) {
			p += 3;
			pl -= 3;
		}
		len = print_option(NULL, 0, opt->type, pl, p);
		if (len < 0)
			return -1;
		e = strlen(prefix) + strlen(opt->var) + len + 4;
		v = val = *ep++ = xmalloc(e);
		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
		if (len != 0)
			print_option(v, len, opt->type, pl, p);
	}

	return ep - env;
}
예제 #11
0
static int do_route (const char *ifname,
					 struct in_addr destination,
					 struct in_addr netmask,
					 struct in_addr gateway,
					 int metric, int change, int del)
{
	struct nlmr *nlm;
	unsigned int ifindex;
	int retval;

	if (! ifname)
		return -1;

	log_route (destination, netmask, gateway, metric, change, del);

	if (! (ifindex = if_nametoindex (ifname))) {
		logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
				ifname);
		return -1;
	}

	nlm = xmalloc (sizeof (struct nlmr));
	memset (nlm, 0, sizeof (struct nlmr));

	nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
	if (change)
		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
	else if (! del)
		nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
	nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE;
	nlm->rt.rtm_family = AF_INET;
	nlm->rt.rtm_table = RT_TABLE_MAIN;

	if (del)
		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
	else {
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
		nlm->rt.rtm_protocol = RTPROT_BOOT;
		if (netmask.s_addr == INADDR_BROADCAST ||
			gateway.s_addr == INADDR_ANY)
			nlm->rt.rtm_scope = RT_SCOPE_LINK;
		else
			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
		nlm->rt.rtm_type = RTN_UNICAST;
	}

	nlm->rt.rtm_dst_len = inet_ntocidr (netmask);
	add_attr_l (&nlm->hdr, sizeof (struct nlmr), RTA_DST,
				&destination.s_addr, sizeof (destination.s_addr));
	if (netmask.s_addr != INADDR_BROADCAST &&
		destination.s_addr != gateway.s_addr)
		add_attr_l (&nlm->hdr, sizeof (struct nlmr), RTA_GATEWAY,
					&gateway.s_addr, sizeof (gateway.s_addr));

	add_attr_32 (&nlm->hdr, sizeof (struct nlmr), RTA_OIF, ifindex);
	add_attr_32 (&nlm->hdr, sizeof (struct nlmr), RTA_PRIORITY, metric);

	retval = send_netlink (&nlm->hdr);
	free (nlm);
	return retval;
}
예제 #12
0
int
if_route(const struct rt *rt, int action)
{
	struct nlmr *nlm;
	int retval = 0;
	struct dhcp_state *state;

	nlm = calloc(1, sizeof(*nlm));
	if (nlm == NULL)
		return -1;
	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
	if (action == 0)
		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
	else if (action == 1)
		nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
	else
		nlm->hdr.nlmsg_type = RTM_DELROUTE;
	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
	nlm->rt.rtm_family = AF_INET;
	nlm->rt.rtm_table = RT_TABLE_MAIN;

	state = D_STATE(rt->iface);
	if (action == -1 || action == -2)
		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
	else {
		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
		/* We only change route metrics for kernel routes */
		if (rt->dest.s_addr ==
		    (state->addr.s_addr & state->net.s_addr) &&
		    rt->net.s_addr == state->net.s_addr)
			nlm->rt.rtm_protocol = RTPROT_KERNEL;
		else
			nlm->rt.rtm_protocol = RTPROT_BOOT;
		if (rt->gate.s_addr == INADDR_ANY ||
		    (rt->gate.s_addr == rt->dest.s_addr &&
			rt->net.s_addr == INADDR_BROADCAST))
			nlm->rt.rtm_scope = RT_SCOPE_LINK;
		else
			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
		nlm->rt.rtm_type = RTN_UNICAST;
	}

	nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
		    &state->addr.s_addr, sizeof(state->addr.s_addr));
	}
	/* If destination == gateway then don't add the gateway */
	if (rt->dest.s_addr != rt->gate.s_addr ||
	    rt->net.s_addr != INADDR_BROADCAST)
		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));

	if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
		add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);

	if (send_netlink(&nlm->hdr) == -1)
		retval = -1;
	free(nlm);
	return retval;
}