void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; #ifndef HAVE_SOCKADDR_SA_LEN char *p = (char *)sa; size_t len; #endif for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; #ifdef HAVE_SOCKADDR_SA_LEN NEXT_SA(sa); #else switch(sa->sa_family) { case AF_INET: len = sizeof(struct sockaddr_in); break; case AF_LINK: len = sizeof(struct sockaddr_dl); break; default: len = 0; } sa = (struct sockaddr *) (p + len); p = (char *)sa; #endif } else rti_info[i] = NULL; } }
void get_rtaddr(int flags,struct sockaddr *sa,struct sockaddr **rt_info) { int i; for(i=0 ; i < RTAX_MAX; i++){ if( flags & (1 << i)){ rt_info[i] = sa; NEXT_SA(sa); }else{ rt_info[i] = NULL; } } }
void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; NEXT_SA(sa); } else rti_info[i] = NULL; } }
int get_bind_addr(bin_addr *dest, struct addrinfo *ba) { /* list interface name/address * fixed size buffer limits number of recognizable interfaces. * buf size = sizeof(struct ifreq) * 256 interface = 8192 */ int i, ent, sockfd, len; char *ptr, buf[sizeof(struct ifreq) * MAXNUM_IF]; struct ifconf ifc; struct ifreq *ifr; struct sockaddr_in *sinptr; struct if_list ifl[MAXNUM_IF]; pid_t pid; ssize_t n; struct rt_msghdr *rtm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_in *sin; struct sockaddr_dl *sdl; struct in_addr ia; struct addrinfo hints, *res, *res0; int error; char host[256]; int found = 0; /* IPv6 routing is not implemented yet */ switch (dest->atype) { case S5ATIPV4: memcpy(&ia, &(dest->v4_addr), 4); break; case S5ATIPV6: return -1; case S5ATFQDN: memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_INET; memcpy(host, &dest->fqdn, dest->len_fqdn); host[dest->len_fqdn] = '\0'; error = getaddrinfo(host, NULL, &hints, &res0); if (error) { return -1; } for (res = res0; res; res = res->ai_next) { if (res->ai_family != AF_INET) continue; sin = (struct sockaddr_in *)res->ai_addr; memcpy(&ia, &(sin->sin_addr), sizeof(ia)); found++; break; } freeaddrinfo(res0); if (!found) return -1; break; default: return -1; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); ifc.ifc_len = sizeof(buf); ifc.ifc_req = (struct ifreq *) buf; ioctl(sockfd, SIOCGIFCONF, &ifc); close(sockfd); i = ent = 0; for (ptr = buf; ptr < buf + ifc.ifc_len; ) { ifr = (struct ifreq *) ptr; len = sizeof(struct sockaddr); #ifdef HAVE_SOCKADDR_SA_LEN if (ifr->ifr_addr.sa_len > len) len = ifr->ifr_addr.sa_len; /* length > 16 */ #endif ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ switch (ifr->ifr_addr.sa_family) { case AF_INET: strncpy(ifl[i].if_name, ifr->ifr_name, IFNAMSIZ); sinptr = (struct sockaddr_in *) &ifr->ifr_addr; memcpy(&ifl[i].if_addr, &sinptr->sin_addr, sizeof(struct in_addr)); i++; break; default: break; } } ent = i; /* number of interfaces */ /* get routing */ setreuid(PROCUID, 0); sockfd = socket(AF_ROUTE, SOCK_RAW, 0); /* need superuser privileges */ setreuid(0, PROCUID); if (sockfd < 0) { /* socket error */ return(-1); } memset(buf, 0, sizeof buf); rtm = (struct rt_msghdr *) buf; rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in) + sizeof(struct sockaddr_dl); rtm->rtm_version = RTM_VERSION; rtm->rtm_type = RTM_GET; rtm->rtm_addrs = RTA_DST|RTA_IFP; rtm->rtm_pid = pid = getpid(); rtm->rtm_seq = SEQ; sin = (struct sockaddr_in *) (buf + sizeof(struct rt_msghdr)); sin->sin_family = AF_INET; #ifdef HAVE_SOCKADDR_SA_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif memcpy(&(sin->sin_addr), &ia, sizeof(struct in_addr)); #ifdef HAVE_SOCKADDR_SA_LEN sa = (struct sockaddr *)sin; NEXT_SA(sa); sdl = (struct sockaddr_dl *)sa; sdl->sdl_len = sizeof(struct sockaddr_dl); #else sdl = (struct sockaddr_dl *) (buf + ROUNDUP(sizeof(struct rt_msghdr), sizeof(u_long)) + ROUNDUP(sizeof(struct sockaddr_in), sizeof(u_long))); #endif sdl->sdl_family = AF_LINK; write(sockfd, rtm, rtm->rtm_msglen); do { n = read(sockfd, rtm, sizeof buf); } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ || rtm->rtm_pid != pid); close(sockfd); rtm = (struct rt_msghdr *) buf; sa = (struct sockaddr *) (rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); ba->ai_family = AF_INET; /* IPv4 */ ba->ai_socktype = SOCK_STREAM; ba->ai_protocol = IPPROTO_TCP; sin = (struct sockaddr_in *)ba->ai_addr; sin->sin_family = AF_INET; #ifdef HAVE_SOCKADDR_SA_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif ba->ai_addrlen = sizeof(struct sockaddr_in); if ( (sa = rti_info[RTAX_IFP]) != NULL) { sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen > 0) { for (i=0; i<ent; i++) { if (memcmp(ifl[i].if_name, sdl->sdl_data, sdl->sdl_nlen) == 0) { memcpy(&sin->sin_addr, &ifl[i].if_addr, sizeof(struct in_addr)); return(0); } } } } return(-1); }