📄 su_localinfo.c
字号:
/* Get the list of known IP address from the kernel */ if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) { /* can't get number of interfaces -- fall back */ SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; } SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n", numifs)); if (numifs < 0)# endif /* Default to 64 interfaces. Enough? */ numifs = 64; if (numifs == 0) return 0; /* * Allocate memory for SIOCGIFCONF ioctl buffer. This memory block is also * used as li_first, first localinfo struct that is returned, so it can be * freed by freelocalinfo() without any complications. */ ifc.ifc_len = numifs * sizeof (struct ifreq); buffer = malloc(sizeof(su_localinfo_t) + ifc.ifc_len + su_xtra); if (!buffer) { SU_DEBUG_1(("su_localinfo: memory exhausted\n")); error = ELI_MEMORY; goto err; } li_first = (su_localinfo_t *)buffer; memset(li_first, 0, sizeof(su_localinfo_t) + su_xtra); ifc.ifc_buf = buffer + sizeof(su_localinfo_t) + su_xtra;#if HAVE_OPEN_C if (ioctl(s, SIOCGIFACTIVECONF, (char *)&ifc) < 0) { SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; }#else if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; }#endif buffer = ifc.ifc_buf + ifc.ifc_len; for (ifr = ifc.ifc_req; (void *)ifr < (void *)buffer; ifr = ifr_next) { struct ifreq ifreq[1]; int scope, if_index, flags = 0, gni_flags = 0; char *if_name; su_sockaddr_t su2[1];#if SA_LEN if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) ifr_next = (struct ifreq *) (ifr->ifr_addr.sa_len + (char *)(&ifr->ifr_addr)); else#else ifr_next = ifr + 1;#endif if_name = ifr->ifr_name;#if defined(SIOCGIFINDEX) ifreq[0] = *ifr; if (ioctl(s, SIOCGIFINDEX, ifreq) < 0) { SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; }#if HAVE_IFR_INDEX if_index = ifreq->ifr_index;#elif HAVE_IFR_IFINDEX if_index = ifreq->ifr_ifindex;#else#error Unknown index field in struct ifreq#endif#else#warning su_localinfo() cannot map interface name to number if_index = 0;#endif SU_DEBUG_9(("su_localinfo: if %s with index %d\n", if_name, if_index));#if HAVE_OPEN_C su_close(s); li = calloc(1, sizeof(su_localinfo_t)); sa = calloc(1, sizeof(su_sockaddr_t)); if (su_get_local_ip_addr(sa) < 0) goto err; li->li_family = sa->su_family; li->li_scope = LI_SCOPE_GLOBAL /* scope */; li->li_index = if_index; li->li_addrlen = su_sockaddr_size(sa); li->li_addr = sa; if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0) goto err; if (canonname) { if (strchr(canonname, ':') || strspn(canonname, "0123456789.") == strlen(canonname)) li->li_flags |= LI_NUMERIC; } else li->li_flags = 0; li->li_canonname = canonname; canonname = NULL; *rresult = li; return 0;#endif#if defined(SIOCGIFFLAGS) ifreq[0] = *ifr; if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) { SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; } /* Do not include interfaces that are down unless explicitly asked */ if ((ifreq->ifr_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0) { SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n", if_name, if_index)); continue; }#elif defined(SIOCGIFACTIVECONF)/* Handled above in SIOCGIFACTIVECONF vs. SIOCGIFCONF*/#else#error su_localinfo() cannot determine interface status#endif#if 0 *ifreq = *ifr; ifreq->ifr_addr.sa_family = AF_INET; if (ioctl(s, SIOCGIFADDR, ifreq) < 0) { SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n", su_strerror(su_errno()))); error = ELI_SYSTEM; goto err; } ifr->ifr_addr = ifreq->ifr_addr;#endif su = (su_sockaddr_t *)&ifr->ifr_addr; if (SU_HAS_INADDR_ANY(su)) continue; scope = li_scope4(su->su_sin.sin_addr.s_addr); if ((hints->li_scope && (hints->li_scope & scope) == 0) || (hints->li_ifname && strcmp(hints->li_ifname, if_name) != 0) || (hints->li_index && hints->li_index != if_index)) continue;#if SU_HAVE_IN6 if (su_xtra) { /* Map IPv4 address to IPv6 address */ memset(su2, 0, sizeof(*su2)); su2->su_family = AF_INET6; ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff); ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr; su = su2; }#endif if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK) gni_flags = NI_NUMERICHOST; if ((error = li_name(hints, gni_flags, su, &canonname)) < 0) goto err; else if (error > 0) continue; if (canonname) if (strchr(canonname, ':') || strspn(canonname, "0123456789.") == strlen(canonname)) flags |= LI_NUMERIC; if (li_first) li = li_first; /* Use li_first with all ifr structs to be freed */ else if (!(li = calloc(1, (sizeof *li) + su_xtra))) { error = ELI_MEMORY; goto err; } if (!tbf) tbf = li; *lli = li; lli = &li->li_next; if (su_xtra) su = (su_sockaddr_t *)memcpy(li + 1, su, su_xtra); li->li_flags = flags; li->li_family = su->su_family; li->li_scope = scope; li->li_index = if_index; li->li_addrlen = su_sockaddr_size(su); li->li_addr = su; li->li_canonname = canonname; if (hints->li_flags & LI_IFNAME) li->li_ifname = if_name; canonname = NULL; li_first = NULL; } if (canonname) free(canonname); if (li_first) free(li_first); su_close(s); if (tbf) *rresult = tbf; return 0;err: if (canonname) free(canonname); if (li_first) free(li_first); su_freelocalinfo(tbf); su_close(s); return error;}#endif /* __APPLE_CC__ */#elsestaticint localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult){ /* Kikka #3: resolve hostname */ char hostname[SU_MAXHOST] = ""; char *name, *ifname; struct hostent *h; int i, flags, error, gni_flags = 0; su_localinfo_t *tbf = NULL; su_localinfo_t *li = NULL, **lli = &tbf; su_sockaddr_t *su;#if SU_HAVE_IN6 socklen_t su_sockaddr_size = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : sizeof(struct sockaddr_in); flags = hints->li_flags & (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);#else socklen_t su_sockaddr_size = sizeof(struct sockaddr_in); flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);#endif error = ELI_NOERROR; if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) { if (hints->li_canonname) name = hints->li_canonname; else if (gethostname(name = hostname, sizeof(hostname)) != 0) return ELI_SYSTEM; h = gethostbyname(name); if (name) if (strchr(name, ':') || strspn(name, "0123456789.") == strlen(name)) flags |= LI_NUMERIC; for (i = 0; h && h->h_addr_list[i]; i++) { if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) { error = ELI_MEMORY; goto err; } li->li_flags = flags; li->li_scope = li_scope4(*(uint32_t *)h->h_addr_list[i]); if (li->li_scope == LI_SCOPE_HOST) li->li_index = 1, ifname = "lo"; else li->li_index = 2, ifname = "eth"; li->li_addrlen = su_sockaddr_size; li->li_addr = su = (su_sockaddr_t *)(li + 1); su->su_family = li->li_family = li->li_flags & LI_V4MAPPED ? AF_INET6 : AF_INET;#if SU_HAVE_IN6 if (li->li_flags & LI_V4MAPPED) { ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff); memcpy(&((int32_t*)&su->su_sin6.sin6_addr)[3], h->h_addr_list[i], h->h_length); } else #endif memcpy(&su->su_sin.sin_addr.s_addr, h->h_addr_list[i], h->h_length); if (li->li_flags & LI_IFNAME) li->li_ifname = ifname; if (li->li_scope == LI_SCOPE_HOST || li->li_scope == LI_SCOPE_LINK) gni_flags = NI_NUMERICHOST; if ((error = li_name(hints, gni_flags, su, &li->li_canonname)) < 0) goto err; else if (error > 0) { free(li); li = NULL; continue; } else error = ELI_NOADDRESS; *lli = li; lli = &li->li_next; li = NULL; } } if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_HOST)) { if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) { error = ELI_MEMORY; goto err; } li->li_flags = hints->li_flags & (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME); li->li_scope = LI_SCOPE_HOST, li->li_index = 1; if (li->li_flags & LI_IFNAME) li->li_ifname = "lo"; li->li_addrlen = su_sockaddr_size; li->li_addr = su = (su_sockaddr_t *)(li + 1);#if SU_HAVE_IN6 if (li->li_flags & LI_V4MAPPED) { su->su_family = li->li_family = AF_INET6; ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff); ((int32_t*)&su->su_sin6.sin6_addr)[3] = htonl(0x7f000001); } else #endif su->su_family = li->li_family = AF_INET, su->su_sin.sin_addr.s_addr = htonl(0x7f000001); if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0) { goto err; } else if (error > 0) { free(li); li = NULL; } else { *lli = li; lli = &li->li_next; li = NULL; } } *rresult = tbf; return 0;err: if (li) su_freelocalinfo(li); su_freelocalinfo(tbf); return error;}#endif#if USE_LOCALINFO0 || !SU_HAVE_IN6#elif HAVE_PROC_NET_IF_INET6 /** Build a list of local IPv6 addresses and append it to *return_result. */staticint localinfo6(su_localinfo_t const *hints, su_localinfo_t **return_result){ su_localinfo_t *li = NULL; su_sockaddr_t su[1] = {{ 0 }}, *addr; int error = ELI_NOADDRESS; char *canonname = NULL; char line[80]; FILE *f; if ((f = fopen("/proc/net/if_inet6", "r"))) { for (;error;) { struct in6_addr in6; unsigned if_index, prefix_len, scope, flags; int addrlen, if_namelen; char ifname[16]; if (!fgets(line, sizeof(line), f)) { if (feof(f)) error = ELI_NOERROR; break; } if (sscanf(line, "%08x%08x%08x%08x %2x %2x %2x %02x %016s\n", &in6.s6_addr32[0], &in6.s6_addr32[1], &in6.s6_addr32[2], &in6.s6_addr32[3], &if_index, &prefix_len, &scope, &flags, ifname) != 9) break; flags = 0; /* Fix global scope (it is 0) */ if (!scope) scope = LI_SCOPE_GLOBAL; in6.s6_addr32[0] = htonl(in6.s6_addr32[0]); in6.s6_addr32[1] = htonl(in6.s6_addr32[1]); in6.s6_addr32[2] = htonl(in6.s6_addr32[2]); in6.s6_addr32[3] = htonl(in6.s6_addr32[3]); if (IN6_IS_ADDR_V4MAPPED(&in6) || IN6_IS_ADDR_V4COMPAT(&in6)) { uint32_t ip4 = *(uint32_t *)(in6.s6_addr + 12); scope = li_scope4(ip4); } if ((hints->li_scope && (hints->li_scope & scope) == 0) || (hints->li_index && hints->li_index != if_index) || (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0)) continue; su->su_family = AF_INET6; su->su_sin6.sin6_addr = in6; addrlen = su_sockaddr_size(su); if ((error = li_name(hints, 0, su, &canonname)) < 0) break; else if (error > 0) continue; else error = ELI_NOADDRESS; if (canonname && (strchr(canonname, ':') || strspn(canonname, "0123456789.") == strlen(canonname))) flags |= LI_NUMERIC; if (hints->li_flags & LI_IFNAME) if_namelen = strlen(ifname) + 1; else if_namelen = 0; if ((li = calloc(1, sizeof *li + addrlen + if_namelen)) == NULL) { error = ELI_MEMORY; break; } addr = (su_sockaddr_t*)memcpy((li + 1), su, addrlen); *return_result = li; return_result = &li->li_next; li->li_flags = flags; li->li_family = AF_INET6; li->li_scope = scope; li->li_index = if_index; li->li_addr = addr; li->li_addrlen = addrlen; li->li_canonname = canonname; if (if_namelen) li->li_ifname = memcpy(addrlen + (char *)addr, ifname, if_namelen); canonname = NULL; } fclose(f); } if (canonname) free(canonname); return error;}#else/* Use HOSTADDR6 */staticint localinfo6(su_localinfo_t const *hints, su_localinfo_t **rresult){ char *addr, *ifname; int flags, error; su_localinfo_t *li = NULL; su_sockaddr_t *su; int const su_sockaddr_size = sizeof(*su); error = ELI_NOADDRESS;#if defined(__APPLE_CC__) { su_sockaddr_t *sa; int salen = sizeof(*sa); int s; if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) { if ((addr = getenv("HOSTADDR6"))) { li = calloc(1, sizeof(su_localinfo_t)); sa = calloc(1, sizeof(su_sockaddr_t)); sa->su_family = AF_INET6; if (su_inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0) goto err; s = su_socket(AF_INET6, SOCK_DGRAM, 0); if (s == -1) { SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n", su_strerror(su_errno()))); return ELI_SYSTEM; } error = getsockname(s, (struct sockaddr *) sa, &salen); if (error < 0 && errno == SOCKET_ERROR) { SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__, su_strerror(su_errno()))); } error = bind(s, (struct sockaddr *) sa, salen); if (error < 0) { SU_DEBUG_1(("%s: bind() failed: %s\n", __func__, su_strerror(su_errno()))); goto err; } su_close(s); li->li_family = sa->su_family; li->li_scope = LI_SCOPE_GLOBAL; li->li_index = 0; li->li_addrlen = su_sockaddr_size(sa); li->li_addr = sa; if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0) goto err; li->li_flags = NI_NUMERICHOST; } } *rresult = li; return 0; }#endif if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) { if ((addr = getenv("HOSTADDR6"))) { flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME); if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) { error = ELI_MEMORY; goto err; } li->li_flags = flags; li->li_scope = LI_SCOPE_GLOBAL, li->li_index = 2, ifname = "eth"; li->li_addrlen = sizeof(*su); li->li_addr = su = (su_sockaddr_t *)(li + 1); su->su_family = li->li_family = AF_INET6; if (su_inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -