int if_address(const struct interface *iface, const struct in_addr *address, const struct in_addr *netmask, const struct in_addr *broadcast, int action) { int retval; struct ifaliasreq ifa; union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; memset(&ifa, 0, sizeof(ifa)); strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name)); #define ADDADDR(_var, _addr) { \ _s.sa = &_var; \ _s.sin->sin_family = AF_INET; \ _s.sin->sin_len = sizeof(*_s.sin); \ memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \ } ADDADDR(ifa.ifra_addr, address); ADDADDR(ifa.ifra_mask, netmask); if (action >= 0 && broadcast) { ADDADDR(ifa.ifra_broadaddr, broadcast); } #undef ADDADDR if (action < 0) retval = ifioctl(socket_afnet, SIOCDIFADDR, &ifa, curlwp); else retval = ifioctl(socket_afnet, SIOCAIFADDR, &ifa, curlwp); return retval; }
static int do_address (const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast, int del) { int s; struct ifaliasreq ifa; if (! ifname) return -1; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } memset (&ifa, 0, sizeof (ifa)); strcpy (ifa.ifra_name, ifname); #define ADDADDR(_var, _addr) \ { \ union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ _s.sa = &_var; \ _s.sin->sin_family = AF_INET; \ _s.sin->sin_len = sizeof (struct sockaddr_in); \ memcpy (&_s.sin->sin_addr, &_addr, sizeof (struct in_addr)); \ } ADDADDR (ifa.ifra_addr, address); ADDADDR (ifa.ifra_mask, netmask); if (! del) { ADDADDR (ifa.ifra_broadaddr, broadcast); } #undef ADDADDR if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { logger (LOG_ERR, "ioctl %s: %s", del ? "SIOCDIFADDR" : "SIOCAIFADDR", strerror (errno)); close (s); return -1; } close (s); return 0; }
int if_address6(const struct ipv6_addr *a, int action) { int s, r; struct in6_aliasreq ifa; struct in6_addr mask; if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) return -1; memset(&ifa, 0, sizeof(ifa)); strlcpy(ifa.ifra_name, a->iface->name, sizeof(ifa.ifra_name)); /* * We should not set IN6_IFF_TENTATIVE as the kernel should be * able to work out if it's a new address or not. * * We should set IN6_IFF_AUTOCONF, but the kernel won't let us. * This is probably a safety measure, but still it's not entirely right * either. */ #if 0 if (a->autoconf) ifa.ifra_flags |= IN6_IFF_AUTOCONF; #endif #define ADDADDR(v, addr) { \ (v)->sin6_family = AF_INET6; \ (v)->sin6_len = sizeof(*v); \ (v)->sin6_addr = *addr; \ } ADDADDR(&ifa.ifra_addr, &a->addr); ifa_scope(&ifa.ifra_addr, a->iface->index); ipv6_mask(&mask, a->prefix_len); ADDADDR(&ifa.ifra_prefixmask, &mask); ifa.ifra_lifetime.ia6t_vltime = a->prefix_vltime; ifa.ifra_lifetime.ia6t_pltime = a->prefix_pltime; #undef ADDADDR r = ioctl(s, action < 0 ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa); close(s); return r; }
int if_address(const struct interface *iface, const struct in_addr *address, const struct in_addr *netmask, const struct in_addr *broadcast, int action) { int s, r; struct ifaliasreq ifa; union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return -1; memset(&ifa, 0, sizeof(ifa)); strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name)); #define ADDADDR(_var, _addr) { \ _s.sa = &_var; \ _s.sin->sin_family = AF_INET; \ _s.sin->sin_len = sizeof(*_s.sin); \ memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \ } ADDADDR(ifa.ifra_addr, address); ADDADDR(ifa.ifra_mask, netmask); if (action >= 0 && broadcast) { ADDADDR(ifa.ifra_broadaddr, broadcast); } #undef ADDADDR r = ioctl(s, action < 0 ? SIOCDIFADDR : action == 2 ? SIOCSIFADDR : SIOCAIFADDR, &ifa); close(s); return r; }
/* ARGSUSED4 */ int if_route(const struct interface *iface, const struct in_addr *dest, const struct in_addr *net, const struct in_addr *gate, int metric, int action) { int error; union sockunion { struct sockaddr sa; struct sockaddr_in sin; #ifdef INET6 struct sockaddr_in6 sin6; #endif struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 4]; } rtm; char *bp = rtm.buffer, *p; size_t l; struct mbuf *m; #define ADDSU(_su) { \ l = RT_ROUNDUP(_su.sa.sa_len); \ memcpy(bp, &(_su), l); \ bp += l; \ } #define ADDADDR(_a) { \ memset (&su, 0, sizeof(su)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof(su.sin); \ memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \ ADDSU(su); \ } memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) rtm.hdr.rtm_type = RTM_ADD; else { rtm.hdr.rtm_type = RTM_DELETE; /* shortcircuit a bit for now */ return 0; } rtm.hdr.rtm_flags = RTF_UP; /* None interface subnet routes are static. */ if (gate->s_addr != INADDR_ANY || net->s_addr != iface->net.s_addr || dest->s_addr != (iface->addr.s_addr & iface->net.s_addr)) rtm.hdr.rtm_flags |= RTF_STATIC; rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; else { rtm.hdr.rtm_addrs |= RTA_NETMASK; if (rtm.hdr.rtm_flags & RTF_STATIC) rtm.hdr.rtm_flags |= RTF_GATEWAY; if (action >= 0) rtm.hdr.rtm_addrs |= RTA_IFA; } ADDADDR(dest); if (rtm.hdr.rtm_flags & RTF_HOST || !(rtm.hdr.rtm_flags & RTF_STATIC)) { /* Make us a link layer socket for the host gateway */ memset(&su, 0, sizeof(su)); memcpy(&su.sdl, iface->ifp->if_sadl, sizeof(su.sdl)); ADDSU(su); } else { ADDADDR(gate); } if (rtm.hdr.rtm_addrs & RTA_NETMASK) { /* Ensure that netmask is set correctly */ memset(&su, 0, sizeof(su)); su.sin.sin_family = AF_INET; su.sin.sin_len = sizeof(su.sin); memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr)); p = su.sa.sa_len + (char *)&su; for (su.sa.sa_len = 0; p > (char *)&su;) if (*--p != 0) { su.sa.sa_len = 1 + p - (char *)&su; break; } ADDSU(su); } if (rtm.hdr.rtm_addrs & RTA_IFA) ADDADDR(&iface->addr); m = m_gethdr(M_WAIT, MT_DATA); m->m_pkthdr.len = rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; m->m_len = 0; m_copyback(m, 0, l, &rtm); /* XXX: no check */ solock(routeso); #if __NetBSD_Prereq__(7,99,26) error = routeso->so_proto->pr_usrreqs->pr_send(routeso, m, NULL, NULL, curlwp); #else error = routeso->so_proto->pr_output(m, routeso); #endif sounlock(routeso); return error; }
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; }
/* ARGSUSED4 */ int if_route(const struct interface *iface, const struct in_addr *dest, const struct in_addr *net, const struct in_addr *gate, _unused int metric, int action) { union sockunion { struct sockaddr sa; struct sockaddr_in sin; #ifdef INET6 struct sockaddr_in6 sin6; #endif struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 4]; } rtm; char *bp = rtm.buffer, *p; size_t l; int retval = 0; #define ADDSU(_su) { \ l = ROUNDUP(_su.sa.sa_len); \ memcpy(bp, &(_su), l); \ bp += l; \ } #define ADDADDR(_a) { \ memset (&su, 0, sizeof(su)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof(su.sin); \ memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \ ADDSU(su); \ } memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) rtm.hdr.rtm_type = RTM_ADD; else rtm.hdr.rtm_type = RTM_DELETE; rtm.hdr.rtm_flags = RTF_UP; /* None interface subnet routes are static. */ if (gate->s_addr != INADDR_ANY || net->s_addr != iface->net.s_addr || dest->s_addr != (iface->addr.s_addr & iface->net.s_addr)) rtm.hdr.rtm_flags |= RTF_STATIC; rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; else { rtm.hdr.rtm_addrs |= RTA_NETMASK; if (rtm.hdr.rtm_flags & RTF_STATIC) rtm.hdr.rtm_flags |= RTF_GATEWAY; if (action >= 0) rtm.hdr.rtm_addrs |= RTA_IFA; } ADDADDR(dest); if (rtm.hdr.rtm_flags & RTF_HOST || !(rtm.hdr.rtm_flags & RTF_STATIC)) { /* Make us a link layer socket for the host gateway */ memset(&su, 0, sizeof(su)); su.sdl.sdl_len = sizeof(struct sockaddr_dl); link_addr(iface->name, &su.sdl); ADDSU(su); } else ADDADDR(gate); if (rtm.hdr.rtm_addrs & RTA_NETMASK) { /* Ensure that netmask is set correctly */ memset(&su, 0, sizeof(su)); su.sin.sin_family = AF_INET; su.sin.sin_len = sizeof(su.sin); memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr)); p = su.sa.sa_len + (char *)&su; for (su.sa.sa_len = 0; p > (char *)&su;) if (*--p != 0) { su.sa.sa_len = 1 + p - (char *)&su; break; } ADDSU(su); } if (rtm.hdr.rtm_addrs & RTA_IFA) ADDADDR(&iface->addr); rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; if (write(r_fd, &rtm, l) == -1) retval = -1; 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) { if (! ifname) return -1; char *destd = strdup (inet_ntoa (destination)); char *gend = strdup (inet_ntoa (netmask)); logger (LOG_INFO, "%s route to %s (%s) via %s", change ? "changing" : del ? "removing" : "adding", destd, gend, inet_ntoa(gateway)); if (destd) free (destd); if (gend) free (gend); int s; if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } struct rtm { struct rt_msghdr hdr; struct sockaddr_in destination; struct sockaddr_in gateway; struct sockaddr_in netmask; } rtm; memset (&rtm, 0, sizeof (struct rtm)); rtm.hdr.rtm_version = RTM_VERSION; static int seq; rtm.hdr.rtm_seq = ++seq; rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; rtm.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; if (netmask.s_addr == 0xffffffff) rtm.hdr.rtm_flags |= RTF_HOST; 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); ADDADDR (rtm.gateway, 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; }
int if_route6(const struct rt6 *rt, int action) { union sockunion { struct sockaddr sa; struct sockaddr_in6 sin; struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 4]; } rtm; char *bp = rtm.buffer; size_t l; int retval = 0; const struct ipv6_addr_l *lla; /* KAME based systems want to store the scope inside the sin6_addr * for link local addreses */ #ifdef __KAME__ #define SCOPE { \ if (IN6_IS_ADDR_LINKLOCAL(&su.sin.sin6_addr)) { \ uint16_t scope = htons(su.sin.sin6_scope_id); \ memcpy(&su.sin.sin6_addr.s6_addr[2], &scope, \ sizeof(scope)); \ su.sin.sin6_scope_id = 0; \ } \ } #else #define SCOPE #endif #define ADDSU { \ l = RT_ROUNDUP(su.sa.sa_len); \ memcpy(bp, &su, l); \ bp += l; \ } #define ADDADDRS(addr, scope) { \ memset(&su, 0, sizeof(su)); \ su.sin.sin6_family = AF_INET6; \ su.sin.sin6_len = sizeof(su.sin); \ (&su.sin)->sin6_addr = *addr; \ su.sin.sin6_scope_id = scope; \ SCOPE; \ ADDSU; \ } #define ADDADDR(addr) ADDADDRS(addr, 0) memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) rtm.hdr.rtm_type = RTM_ADD; else rtm.hdr.rtm_type = RTM_DELETE; rtm.hdr.rtm_flags = RTF_UP; /* None interface subnet routes are static. */ if (IN6_IS_ADDR_UNSPECIFIED(&rt->dest) && IN6_IS_ADDR_UNSPECIFIED(&rt->net)) rtm.hdr.rtm_flags |= RTF_GATEWAY; #ifdef RTF_CLONING else rtm.hdr.rtm_flags |= RTF_CLONING; #endif rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; if (action >= 0) rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA; ADDADDR(&rt->dest); if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) { lla = ipv6_linklocal(rt->iface); if (lla == NULL) /* unlikely as we need a LL to get here */ return -1; ADDADDRS(&lla->addr, rt->iface->index); } else { lla = NULL; ADDADDRS(&rt->gate, rt->iface->index); } if (rtm.hdr.rtm_addrs & RTA_NETMASK) { if (rtm.hdr.rtm_flags & RTF_GATEWAY) { memset(&su, 0, sizeof(su)); su.sin.sin6_family = AF_INET6; ADDSU; } else ADDADDR(&rt->net); } if (rtm.hdr.rtm_addrs & RTA_IFP) { /* Make us a link layer socket for the host gateway */ memset(&su, 0, sizeof(su)); su.sdl.sdl_len = sizeof(struct sockaddr_dl); link_addr(rt->iface->name, &su.sdl); ADDSU; } if (rtm.hdr.rtm_addrs & RTA_IFA) { if (lla == NULL) { lla = ipv6_linklocal(rt->iface); if (lla == NULL) /* unlikely */ return -1; } ADDADDRS(&lla->addr, rt->iface->index); } #undef ADDADDR #undef ADDSU #undef SCOPE if (action >= 0 && rt->mtu) { rtm.hdr.rtm_inits |= RTV_MTU; rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu; } rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; if (write(r_fd, &rtm, l) == -1) retval = -1; return retval; }
int if_route(const struct rt *rt, int action) { const struct dhcp_state *state; union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 4]; } rtm; char *bp = rtm.buffer; size_t l; int retval = 0; #define ADDSU { \ l = RT_ROUNDUP(su.sa.sa_len); \ memcpy(bp, &su, l); \ bp += l; \ } #define ADDADDR(addr) { \ memset(&su, 0, sizeof(su)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof(su.sin); \ (&su.sin)->sin_addr = *addr; \ ADDSU; \ } state = D_CSTATE(rt->iface); memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) rtm.hdr.rtm_type = RTM_ADD; else rtm.hdr.rtm_type = RTM_DELETE; rtm.hdr.rtm_flags = RTF_UP; /* None interface subnet routes are static. */ if (rt->gate.s_addr != INADDR_ANY || rt->net.s_addr != state->net.s_addr || rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr)) rtm.hdr.rtm_flags |= RTF_STATIC; rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; if (rt->dest.s_addr == rt->gate.s_addr && rt->net.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) && rt->net.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY; else { rtm.hdr.rtm_addrs |= RTA_NETMASK; if (rtm.hdr.rtm_flags & RTF_STATIC) rtm.hdr.rtm_flags |= RTF_GATEWAY; if (action >= 0) rtm.hdr.rtm_addrs |= RTA_IFA; } ADDADDR(&rt->dest); if ((rtm.hdr.rtm_flags & RTF_HOST && rt->gate.s_addr != htonl(INADDR_LOOPBACK)) || !(rtm.hdr.rtm_flags & RTF_STATIC)) { /* Make us a link layer socket for the host gateway */ memset(&su, 0, sizeof(su)); su.sdl.sdl_len = sizeof(struct sockaddr_dl); link_addr(rt->iface->name, &su.sdl); ADDSU; } else ADDADDR(&rt->gate); if (rtm.hdr.rtm_addrs & RTA_NETMASK) ADDADDR(&rt->net); if (rtm.hdr.rtm_addrs & RTA_IFP) { /* Make us a link layer socket for the host gateway */ memset(&su, 0, sizeof(su)); su.sdl.sdl_len = sizeof(struct sockaddr_dl); link_addr(rt->iface->name, &su.sdl); ADDSU; } if (rtm.hdr.rtm_addrs & RTA_IFA) ADDADDR(&state->addr); #undef ADDADDR #undef ADDSU rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; if (write(r_fd, &rtm, l) == -1) retval = -1; return retval; }
int if_route6(const struct rt6 *rt, int action) { union sockunion { struct sockaddr sa; struct sockaddr_in6 sin; struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 5]; } rtm; char *bp = rtm.buffer; size_t l; int s, retval; const struct ipv6_addr *lla; if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1) return -1; #define ADDSU { \ l = RT_ROUNDUP(su.sa.sa_len); \ memcpy(bp, &su, l); \ bp += l; \ } #define ADDADDRS(addr, scope) { \ memset(&su, 0, sizeof(su)); \ su.sin.sin6_family = AF_INET6; \ su.sin.sin6_len = sizeof(su.sin); \ (&su.sin)->sin6_addr = *addr; \ if (scope) \ ifa_scope(&su.sin, scope); \ ADDSU; \ } #define ADDADDR(addr) ADDADDRS(addr, 0) memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) rtm.hdr.rtm_type = RTM_ADD; else rtm.hdr.rtm_type = RTM_DELETE; rtm.hdr.rtm_flags = RTF_UP | (int)rt->flags; #ifdef RTF_PINNED if (rtm.hdr.rtm_type != RTM_ADD) rtm.hdr.rtm_flags |= RTF_PINNED; #endif rtm.hdr.rtm_addrs = RTA_DST | RTA_NETMASK; #ifdef SIOCGIFPRIORITY rtm.hdr.rtm_priority = rt->metric; #endif /* None interface subnet routes are static. */ if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) { #ifdef RTF_CLONING rtm.hdr.rtm_flags |= RTF_CLONING; #endif } else rtm.hdr.rtm_flags |= RTF_GATEWAY | RTF_STATIC; if (action >= 0) { rtm.hdr.rtm_addrs |= RTA_GATEWAY; if (!(rtm.hdr.rtm_flags & RTF_REJECT)) rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA; } ADDADDR(&rt->dest); lla = NULL; if (rtm.hdr.rtm_addrs & RTA_GATEWAY) { if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) { if_linkaddr(&su.sdl, rt->iface); ADDSU; } else { ADDADDRS(&rt->gate, rt->iface->index); } } if (rtm.hdr.rtm_addrs & RTA_NETMASK) ADDADDR(&rt->net); if (rtm.hdr.rtm_addrs & RTA_IFP) { if_linkaddr(&su.sdl, rt->iface); ADDSU; } if (rtm.hdr.rtm_addrs & RTA_IFA) { if (lla == NULL) { lla = ipv6_linklocal(rt->iface); if (lla == NULL) /* unlikely */ return -1; } ADDADDRS(&lla->addr, rt->iface->index); } #undef ADDADDR #undef ADDSU if (action >= 0 && rt->mtu) { rtm.hdr.rtm_inits |= RTV_MTU; rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu; } rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm); retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0; close(s); return retval; }
int if_route(const struct rt *rt, int action) { const struct dhcp_state *state; union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof(su) * 5]; } rtm; char *bp = rtm.buffer; size_t l; int s, retval; if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1) return -1; #define ADDSU { \ l = RT_ROUNDUP(su.sa.sa_len); \ memcpy(bp, &su, l); \ bp += l; \ } #define ADDADDR(addr) { \ memset(&su, 0, sizeof(su)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof(su.sin); \ (&su.sin)->sin_addr = *addr; \ ADDSU; \ } state = D_CSTATE(rt->iface); memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; rtm.hdr.rtm_addrs = RTA_DST; if (action == 0) rtm.hdr.rtm_type = RTM_CHANGE; else if (action > 0) { rtm.hdr.rtm_type = RTM_ADD; rtm.hdr.rtm_addrs |= RTA_GATEWAY; } else rtm.hdr.rtm_type = RTM_DELETE; rtm.hdr.rtm_flags = RTF_UP; #ifdef RTF_PINNED if (rtm.hdr.rtm_type != RTM_ADD) rtm.hdr.rtm_flags |= RTF_PINNED; #endif #ifdef SIOCGIFPRIORITY rtm.hdr.rtm_priority = rt->metric; #endif /* None interface subnet routes are static. */ if (rt->gate.s_addr != INADDR_ANY || rt->net.s_addr != state->net.s_addr || rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr)) rtm.hdr.rtm_flags |= RTF_STATIC; if (rt->dest.s_addr == rt->gate.s_addr && rt->net.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) && rt->net.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY; else { rtm.hdr.rtm_addrs |= RTA_NETMASK; if (rtm.hdr.rtm_flags & RTF_STATIC) rtm.hdr.rtm_flags |= RTF_GATEWAY; if (action >= 0) rtm.hdr.rtm_addrs |= RTA_IFA; } ADDADDR(&rt->dest); if (rtm.hdr.rtm_addrs & RTA_GATEWAY) { if ((rtm.hdr.rtm_flags & RTF_HOST && rt->gate.s_addr != htonl(INADDR_LOOPBACK)) || !(rtm.hdr.rtm_flags & RTF_STATIC)) { if_linkaddr(&su.sdl, rt->iface); ADDSU; } else ADDADDR(&rt->gate); } if (rtm.hdr.rtm_addrs & RTA_NETMASK) ADDADDR(&rt->net); if (rtm.hdr.rtm_addrs & RTA_IFP) { if_linkaddr(&su.sdl, rt->iface); ADDSU; } if (rtm.hdr.rtm_addrs & RTA_IFA) ADDADDR(&state->addr); #undef ADDADDR #undef ADDSU rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm); retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0; close(s); 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) { int s; struct rtm { struct rt_msghdr hdr; char buffer[sizeof (struct sockaddr_storage) * 3]; } rtm; char *bp = rtm.buffer; static int seq; union sockunion { struct sockaddr sa; struct sockaddr_in sin; #ifdef INET6 struct sockaddr_in6 sin6; #endif struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; int l; if (! ifname) return -1; log_route (destination, netmask, gateway, metric, change, del); if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { 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; /* This order is important */ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; #define ADDADDR(_addr) \ memset (&su, 0, sizeof (struct sockaddr_storage)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof (struct sockaddr_in); \ memcpy (&su.sin.sin_addr, &_addr, sizeof (struct in_addr)); \ l = SA_SIZE (&(su.sa)); \ memcpy (bp, &(su), l); \ bp += l; ADDADDR (destination); if (netmask.s_addr == INADDR_BROADCAST || gateway.s_addr == INADDR_ANY) { /* Make us a link layer socket */ unsigned char *hwaddr; int hwlen = 0; if (netmask.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); memset (&su, 0, sizeof (struct sockaddr_storage)); su.sdl.sdl_len = sizeof (struct sockaddr_dl); su.sdl.sdl_family = AF_LINK; su.sdl.sdl_nlen = strlen (ifname); memcpy (&su.sdl.sdl_data, ifname, su.sdl.sdl_nlen); su.sdl.sdl_alen = hwlen; memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, hwaddr, su.sdl.sdl_alen); l = SA_SIZE (&(su.sa)); memcpy (bp, &su, l); bp += l; free (hwaddr); } else { rtm.hdr.rtm_flags |= RTF_GATEWAY; ADDADDR (gateway); } ADDADDR (netmask); #undef ADDADDR rtm.hdr.rtm_msglen = sizeof (rtm); if (write (s, &rtm, sizeof (rtm)) == -1) { /* 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; }