ssize_t if_sendrawpacket(const struct interface *ifp, int protocol, const void *data, size_t len) { struct iovec iov[2]; struct ether_header hw; int fd; const struct dhcp_state *state; memset(&hw, 0, ETHER_HDR_LEN); memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); hw.ether_type = htons(protocol); iov[0].iov_base = &hw; iov[0].iov_len = ETHER_HDR_LEN; iov[1].iov_base = UNCONST(data); iov[1].iov_len = len; state = D_CSTATE(ifp); if (protocol == ETHERTYPE_ARP) fd = state->arp_fd; else fd = state->raw_fd; return writev(fd, iov, 2); }
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_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; }