/*FUNCTION*------------------------------------------------------------- * * Function Name : getaddrinfo * Returned Value : RTCS_OK or error code * Comments : * Get a list of IP addresses and port numbers for host hostname and service servname. * *END*-----------------------------------------------------------------*/ int32_t getaddrinfo ( const char *hostname, /* host name or IP or NULL */ const char *servname, /* service name or port number */ const struct addrinfo *hints, /* set flags */ struct addrinfo **res /* [OUT]list of address structures */ ) { const char *proto = NULL; int family; int socktype; int flags; int protocol; struct addrinfo *ai; struct addrinfo *ai_list; uint16_t port; uint16_t err; uint16_t i; int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,int, int); /*hostname and send name can not be NULL in same time*/ if (hostname == NULL && servname == NULL) { return (EAI_NONAME); } proto = NULL; if (hints != NULL) { if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) { return (EAI_BADFLAGS); } if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) { _task_errno = MQX_EINVAL; return (EAI_SYSTEM); } family = hints->ai_family; socktype = hints->ai_socktype; protocol = hints->ai_protocol; flags = hints->ai_flags; /* looking for correct protocol depended on family and socket type */ switch (family) { case AF_UNSPEC: #if RTCSCFG_ENABLE_IP4 case AF_INET: #endif #if RTCSCFG_ENABLE_IP6 case AF_INET6: #endif if(hints->ai_socktype == 0) { break; }else if(hints->ai_socktype == SOCK_STREAM) { proto = "tcp"; }else if(hints->ai_socktype == SOCK_DGRAM) { proto = "udp"; }else{ return (EAI_SOCKTYPE); } break; default: return (EAI_FAMILY); }/* end of switch (family) */ } else { protocol = 0; family = 0; socktype = 0; flags = 0; }/* end of (hints != NULL) */ if(proto !=NULL) { protocol = (strcmp(proto,"tcp")) ? 2 : 1; } /* * Ok, only AF_INET and AF_INET6 left. */ /*************************************/ /* * First, look up the service port if it was * requested. If the socket type wasn't specified, then * try and figure it out. */ if (servname != NULL) { char *e; port = strtol(servname, &e, 10); if (*e == '\0') //*e - end pointer { /* Port number.*/ if (socktype == 0) //Not sure that it is necessary here { return (EAI_SOCKTYPE); } /* When port will be in network endian, do mqx_htons(&tmp,(uint16_t) port); */ } else { /* We use only port number. We do not use a service name */ return (EAI_SERVICE); }/*end of (*e == '\0')*/ } else { port = 0; } /* end (servname != NULL) */ /* * Next, deal with just a service name, and no hostname. * (we verified that one of them was non-null up above). */ ai_list = NULL; if (hostname == NULL && (flags & AI_PASSIVE) != 0) { #if RTCSCFG_ENABLE_IP4 if (family == AF_INET || family == 0) { /* Allocate an addrinfo structure, and a sockaddr structure */ ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); if (ai == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; ai->ai_next = ai_list; ai_list = ai; } #endif #if RTCSCFG_ENABLE_IP6 if (family == AF_INET6 || family == 0) { ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); if (ai == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN6(ai->ai_addr)->sin6_port = port; ai->ai_next = ai_list; ai_list = ai; } #endif *res = ai; return (0); }/* end of (hostname == NULL && (flags & AI_PASSIVE) != 0) */ /* * If the host is not NULL and the family isn't specified or AI_NUMERICHOST * specified, check first to see if it is a numeric address. * Though the gethostbyname2() routine * will recognize numeric addresses, it will only recognize * the format that it is being called for. Thus, a numeric * AF_INET address will be treated by the AF_INET6 call as * a domain name, and vice versa. Checking for both numerics * here avoids that. */ if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) { char abuf[sizeof(struct in6_addr)]; char nbuf[NI_MAXHOST]; int addrsize, addroff; char *p, *ep; char ntmp[NI_MAXHOST]; uint32_t scopeid; /* * Scope identifier portion. * scope id must be a decimal number */ ntmp[0] = '\0'; if (strchr(hostname, '%') != NULL) { strncpy(ntmp, hostname, sizeof(ntmp) - 1); ntmp[sizeof(ntmp) - 1] = '\0'; /*Returns a pointer to the first occurrence of character '%'.*/ p = strchr(ntmp, '%'); ep = NULL; /* * Vendors may want to support non-numeric * scopeid around here. */ if (p != NULL) { scopeid = (uint32_t)strtoul(p + 1, &ep, 10); } if (p != NULL && ep != NULL && ep[0] == '\0') { *p = '\0'; }else { ntmp[0] = '\0'; scopeid = 0; } } else{ scopeid = 0; } /* end of (strchr(hostname, '%') != NULL) */ /* * Converts a human readable IP address into an address * family appropriate 32bit or 128bit binary structure. */ if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf,sizeof( *((struct in_addr *)abuf)))== RTCS_OK) { if (family == AF_INET6) { /* * Convert to a V4 mapped address. */ struct in6_addr *a6 = (struct in6_addr *)abuf; memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); memset(&a6->s6_addr[10], 0xff, 2); memset(&a6->s6_addr[0], 0, 10); goto inet6_addr; } addrsize = sizeof(struct in_addr); addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; family = AF_INET; goto common; } else if (ntmp[0] != '\0' && inet_pton(AF_INET6, ntmp, abuf,sizeof(struct in6_addr)) == RTCS_OK) { if (family && family != AF_INET6) { return (EAI_NONAME); } addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; goto common; } else if (inet_pton(AF_INET6, hostname, abuf,sizeof(struct in6_addr)) == RTCS_OK) { if (family != 0 && family != AF_INET6) { return (EAI_NONAME); } inet6_addr: addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; common: ai = ai_clone(ai_list, family); if (ai == NULL) { return (EAI_MEMORY); } ai_list = ai; ai->ai_socktype = socktype; //ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); if (flags & AI_CANONNAME) { if (ai->ai_family == AF_INET6) { SIN6(ai->ai_addr)->sin6_scope_id = scopeid; } if (getnameinfo( ai->ai_addr, ai->ai_addrlen, nbuf, sizeof(nbuf), NULL, 0, NI_NUMERICHOST ) == 0) { ai->ai_canonname = strdup(nbuf); if (ai->ai_canonname == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } } else { /* XXX raise error? */ ai->ai_canonname = NULL; } }/*end of (flags & AI_CANONNAME)*/ goto done; } else if ((flags & AI_NUMERICHOST) != 0) { return (EAI_NONAME); } }/* end of (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)== 1) */ set_order(family, net_order); for (i = 0; i < FOUND_MAX; i++) { if (net_order[i] == NULL) break; err = (net_order[i])(hostname, flags, &ai_list, socktype, port); if (err != 0) return (err); } if (ai_list == NULL) return (EAI_NODATA); done: ai_list->ai_protocol = protocol; ai_list->ai_flags = flags; ai_list = ai_reverse(ai_list); *res = ai_list; return (0); }
int lwres_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct servent *sp; const char *proto; int family, socktype, flags, protocol; struct addrinfo *ai, *ai_list; int port, err, i; int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, int, int); if (hostname == NULL && servname == NULL) return (EAI_NONAME); proto = NULL; if (hints != NULL) { if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) return (EAI_BADFLAGS); if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) { errno = EINVAL; return (EAI_SYSTEM); } family = hints->ai_family; socktype = hints->ai_socktype; protocol = hints->ai_protocol; flags = hints->ai_flags; switch (family) { case AF_UNSPEC: switch (hints->ai_socktype) { case SOCK_STREAM: proto = "tcp"; break; case SOCK_DGRAM: proto = "udp"; break; } break; case AF_INET: case AF_INET6: switch (hints->ai_socktype) { case 0: break; case SOCK_STREAM: proto = "tcp"; break; case SOCK_DGRAM: proto = "udp"; break; case SOCK_RAW: break; default: return (EAI_SOCKTYPE); } break; #ifdef AF_LOCAL case AF_LOCAL: switch (hints->ai_socktype) { case 0: break; case SOCK_STREAM: break; case SOCK_DGRAM: break; default: return (EAI_SOCKTYPE); } break; #endif default: return (EAI_FAMILY); } } else { protocol = 0; family = 0; socktype = 0; flags = 0; } #ifdef AF_LOCAL /* * First, deal with AF_LOCAL. If the family was not set, * then assume AF_LOCAL if the first character of the * hostname/servname is '/'. */ if (hostname != NULL && (family == AF_LOCAL || (family == 0 && *hostname == '/'))) return (get_local(hostname, socktype, res)); if (servname != NULL && (family == AF_LOCAL || (family == 0 && *servname == '/'))) return (get_local(servname, socktype, res)); #endif /* * Ok, only AF_INET and AF_INET6 left. */ ai_list = NULL; /* * First, look up the service name (port) if it was * requested. If the socket type wasn't specified, then * try and figure it out. */ if (servname != NULL) { char *e; port = strtol(servname, &e, 10); if (*e == '\0') { if (socktype == 0) return (EAI_SOCKTYPE); if (port < 0 || port > 65535) return (EAI_SERVICE); port = htons((unsigned short) port); } else { sp = getservbyname(servname, proto); if (sp == NULL) return (EAI_SERVICE); port = sp->s_port; if (socktype == 0) { if (strcmp(sp->s_proto, "tcp") == 0) socktype = SOCK_STREAM; else if (strcmp(sp->s_proto, "udp") == 0) socktype = SOCK_DGRAM; } } } else port = 0; /* * Next, deal with just a service name, and no hostname. * (we verified that one of them was non-null up above). */ if (hostname == NULL && (flags & AI_PASSIVE) != 0) { if (family == AF_INET || family == 0) { ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); if (ai == NULL) return (EAI_MEMORY); ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; ai->ai_next = ai_list; ai_list = ai; } if (family == AF_INET6 || family == 0) { ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); if (ai == NULL) { lwres_freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN6(ai->ai_addr)->sin6_port = port; ai->ai_next = ai_list; ai_list = ai; } *res = ai_list; return (0); } /* * If the family isn't specified or AI_NUMERICHOST specified, * check first to see if it is a numeric address. * Though the gethostbyname2() routine * will recognize numeric addresses, it will only recognize * the format that it is being called for. Thus, a numeric * AF_INET address will be treated by the AF_INET6 call as * a domain name, and vice versa. Checking for both numerics * here avoids that. */ if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) { char abuf[sizeof(struct in6_addr)]; char nbuf[NI_MAXHOST]; int addrsize, addroff; #ifdef LWRES_HAVE_SIN6_SCOPE_ID char *p, *ep; char ntmp[NI_MAXHOST]; lwres_uint32_t scopeid; #endif #ifdef LWRES_HAVE_SIN6_SCOPE_ID /* * Scope identifier portion. */ ntmp[0] = '\0'; if (strchr(hostname, '%') != NULL) { strncpy(ntmp, hostname, sizeof(ntmp) - 1); ntmp[sizeof(ntmp) - 1] = '\0'; p = strchr(ntmp, '%'); ep = NULL; /* * Vendors may want to support non-numeric * scopeid around here. */ if (p != NULL) scopeid = (lwres_uint32_t)strtoul(p + 1, &ep, 10); if (p != NULL && ep != NULL && ep[0] == '\0') *p = '\0'; else { ntmp[0] = '\0'; scopeid = 0; } } else scopeid = 0; #endif if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf) == 1) { if (family == AF_INET6) { /* * Convert to a V4 mapped address. */ struct in6_addr *a6 = (struct in6_addr *)abuf; memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); memset(&a6->s6_addr[10], 0xff, 2); memset(&a6->s6_addr[0], 0, 10); goto inet6_addr; } addrsize = sizeof(struct in_addr); addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; family = AF_INET; goto common; #ifdef LWRES_HAVE_SIN6_SCOPE_ID } else if (ntmp[0] != '\0' && lwres_net_pton(AF_INET6, ntmp, abuf) == 1) { if (family && family != AF_INET6) return (EAI_NONAME); addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; goto common; #endif } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) { if (family != 0 && family != AF_INET6) return (EAI_NONAME); inet6_addr: addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; common: ai = ai_clone(ai_list, family); if (ai == NULL) return (EAI_MEMORY); ai_list = ai; ai->ai_socktype = socktype; SIN(ai->ai_addr)->sin_port = port; memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); if (flags & AI_CANONNAME) { #if defined(LWRES_HAVE_SIN6_SCOPE_ID) if (ai->ai_family == AF_INET6) SIN6(ai->ai_addr)->sin6_scope_id = scopeid; #endif if (lwres_getnameinfo(ai->ai_addr, ai->ai_addrlen, nbuf, sizeof(nbuf), NULL, 0, NI_NUMERICHOST) == 0) { ai->ai_canonname = strdup(nbuf); if (ai->ai_canonname == NULL) return (EAI_MEMORY); } else { /* XXX raise error? */ ai->ai_canonname = NULL; } } goto done; } else if ((flags & AI_NUMERICHOST) != 0) { return (EAI_NONAME); } } set_order(family, net_order); for (i = 0; i < FOUND_MAX; i++) { if (net_order[i] == NULL) break; err = (net_order[i])(hostname, flags, &ai_list, socktype, port); if (err != 0) return (err); } if (ai_list == NULL) return (EAI_NODATA); done: ai_list = ai_reverse(ai_list); *res = ai_list; return (0); }
/************************************************************************ * NAME: add_ip * RETURNS: 0 if OK. * DESCRIPTION: Try to Resolve IP address using DNS Client. *************************************************************************/ static int add_ip(int family, const char *hostname, int flags, struct addrinfo **aip, int socktype, int port) { struct addrinfo *ai; int result; char *ip_loop; _mem_size ip_length; DNSCLN_TYPE dns_type; DNSCLN_RECORD_STRUCT *dns_record_list = NULL; DNSCLN_PARAM_STRUCT dns_params; int i; #if RTCSCFG_ENABLE_IP4 if(family == AF_INET) { ip_loop = v4_loop; ip_length = sizeof(in_addr); dns_type = DNSCLN_TYPE_A; } else #endif #if RTCSCFG_ENABLE_IP6 if(family == AF_INET6) { ip_loop = v6_loop; ip_length = sizeof(in6_addr); dns_type = DNSCLN_TYPE_AAAA; } else #endif {}; if (hostname == NULL && (flags & AI_PASSIVE) == 0) { /* In this case to get connection * inside host using LOOPBACK interface . */ ai = ai_clone(*aip, AF_INET); if (ai == NULL) { freeaddrinfo(*aip); GAI_EXIT(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN(ai->ai_addr)->sin_port = port; _mem_copy(ip_loop, &SIN(ai->ai_addr)->sin_addr, ip_length); result = EAI_OK; } else { /* If the hostname is not NULL,lets try to resolve it * here we are using RTCS DNS Client to get addr by name. */ for(i=0; (DNSCLN_get_dns_addr(NULL, i, &dns_params.dns_server) == TRUE); i++) { dns_params.name_to_resolve = (char*)hostname; /* Host name to resolve (null-terminated string). */ dns_params.type = dns_type; /* DNS Resource Record Type that is queried. */ /* Send DNS Query.*/ dns_record_list = DNSCLN_query(&dns_params); /* Process DNS result.*/ if(dns_record_list) { /* Resolved.*/ DNSCLN_RECORD_STRUCT *dns_record = dns_record_list; do { ai = ai_clone(*aip, family); if (ai == NULL) { freeaddrinfo(*aip); GAI_EXIT(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; ((struct sockaddr_in *)(ai->ai_addr))->sin_port = port; /* Special case for AF_INET. From network to host endian.*/ if(family == AF_INET) { ((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr = mqx_ntohl(dns_record->data); } else _mem_copy(dns_record->data, &((struct sockaddr_in *)(ai->ai_addr))->sin_addr, ip_length); if (flags & AI_CANONNAME) { if(dns_record->name) { ai->ai_canonname = strdup(dns_record->name); if (ai->ai_canonname == NULL) { GAI_EXIT(EAI_NONAME); } } } dns_record = dns_record->next; } while(dns_record); GAI_EXIT(EAI_OK); } } /* Not resolved.*/ GAI_EXIT(EAI_FAIL); }/* end of (hostname == NULL && (flags & AI_PASSIVE) == 0) */ cleanup: if(dns_record_list) DNSCLN_record_list_free(dns_record_list); return (result); }
static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype, int port) { struct addrinfo *ai; lwres_context_t *lwrctx = NULL; lwres_gabnresponse_t *by = NULL; lwres_addr_t *addr; lwres_result_t lwres; int result = 0; lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); if (lwres != LWRES_R_SUCCESS) ERR(EAI_FAIL); (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); if (hostname == NULL && (flags & AI_PASSIVE) == 0) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); } else { lwres = lwres_getaddrsbyname(lwrctx, hostname, LWRES_ADDRTYPE_V6, &by); if (lwres != LWRES_R_SUCCESS) { if (lwres == LWRES_R_NOTFOUND) goto cleanup; else ERR(EAI_FAIL); } addr = LWRES_LIST_HEAD(by->addrs); while (addr != NULL) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, addr->address, 16); if (flags & AI_CANONNAME) { ai->ai_canonname = strdup(by->realname); if (ai->ai_canonname == NULL) ERR(EAI_MEMORY); } addr = LWRES_LIST_NEXT(addr, link); } } cleanup: if (by != NULL) lwres_gabnresponse_free(lwrctx, &by); if (lwrctx != NULL) { lwres_conf_clear(lwrctx); lwres_context_destroy(&lwrctx); } return (result); }