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); }
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; }
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)); }
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); }
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)); }
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; }
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); }
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; }
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; }
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; }
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; }