/* myip.c : PUBLIC DOMAIN - Jon Mayo - August 22, 2006 * - You may remove any comments you wish, modify this code any way you wish, * and distribute any way you wish. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Updated: August 4, 2020 */ /* finds all network interfaces and shows a little information about them. * some operating systems list interfaces multiple times because of different * flags, modes, etc. if you want to use this code you should be aware that * duplicate interfaces is a possibility */ #include #include #include #include #include #include #include #include #include #define MYIP_MAX_IGNORED 2 /* filter these IPs from the listings */ static struct sockaddr_storage ignored[MYIP_MAX_IGNORED]; static unsigned ignored_len = 0; static void * get_addr(struct sockaddr *sa, size_t *addr_len_out) { if (sa->sa_family == AF_INET) { if (addr_len_out) *addr_len_out = sizeof(struct in_addr); return &((struct sockaddr_in*)sa)->sin_addr; } else if (sa->sa_family == AF_INET6) { if (addr_len_out) *addr_len_out = sizeof(struct in6_addr); return &((struct sockaddr_in6*)sa)->sin6_addr; } else { if (addr_len_out) *addr_len_out = 0; return NULL; // unknown family } } static int add_ignored(int family, const char *addrstr) { if (ignored_len >= MYIP_MAX_IGNORED) return -1; // too many items struct sockaddr_storage *ss = &ignored[ignored_len]; memset(ss, 0, sizeof(*ss)); ss->ss_family = family; void *addr = get_addr((struct sockaddr*)ss, NULL); inet_pton(family, addrstr, addr); ignored_len++; return 0; } static int is_ignored(struct sockaddr *sa) { unsigned i; struct sockaddr_storage *ig; size_t addrlen; void *my_addr = get_addr(sa, &addrlen); for (i = 0, ig = ignored; i < ignored_len; i++, ig++) { if (sa->sa_family == ig->ss_family) { void *ig_addr = get_addr((struct sockaddr*)ig, NULL); if (memcmp(my_addr, ig_addr, addrlen) == 0) return 1; /* match */ } } return 0; /* no match - not ignored */ } static int match_addrs(int family_match, void (*show)(struct sockaddr *sa, socklen_t sa_len)) { struct ifaddrs *a, *curr; if (getifaddrs(&a)) { perror("getifaddrs()"); return -1; } for (curr = a; curr; curr = curr->ifa_next) { int family = curr->ifa_addr->sa_family; if (family == family_match) { socklen_t len = family == AF_INET ? sizeof(struct sockaddr_in) : family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_storage); show(curr->ifa_addr, len); } } freeifaddrs(a); return 0; } static void show_addr(struct sockaddr *sa, socklen_t sa_len) { char addrstr[128]; if (is_ignored(sa)) { return; // ignored } getnameinfo(sa, sa_len, addrstr, sizeof(addrstr), 0, 0, NI_NUMERICHOST); printf("%s ", addrstr); } static int collect_ipv4(void) { return match_addrs(AF_INET, show_addr); } static int collect_ipv6(void) { return match_addrs(AF_INET6, show_addr); } int main() { add_ignored(AF_INET, "127.0.0.1"); add_ignored(AF_INET6, "::1"); if (collect_ipv4()) return EXIT_FAILURE; // putchar('\n'); if (collect_ipv6()) return EXIT_FAILURE; putchar('\n'); return EXIT_SUCCESS; }